Interfaces vs Abstract Classes

As a veteran C programmer I can see why a lot of these things were created or invented. For example, one thing that would have been nice in C is method overloading. I know you can do it the way that printf() does, but, my goodness you need to know your stuff and actually implement a variable argument list in your function... too much work, too much risk.
C or C#? Re most of this thread is C# related; C would be a whole different story.
 
[)roi(];18872328 said:
C or C#? Re most of this thread is C# related; C would be a whole different story.

Yes I accept that, I thought it would be worthy of mentioning that I can see how we arrived at this paradigm in software development. Remember C# and C++ were based on the C foundation, many years ago.
 
Yes I accept that, I thought it would be worthy of mentioning that I can see how we arrived at this paradigm in software development. Remember C# and C++ were based on the C foundation, many years ago.
Point taken. Yet the OOP we have today is far removed from what Alan Kay originally had in mind , that being "Objects would communicate with one another by passing messages" i.e. SmallTalk and far more closer to Objective-C.

Reference: http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en
 
Last edited:
As its said "an example is worth a 1000 words".
So If I get a chance later today I'll try to convert some Swift code that uses a combination of Interfaces, extension methods, generics and classes to produce the foundations of a drawing application, including test mocking and rendering.
 
No guys, dependency(injection, is, awesome, and, will, solve, all, your, problems, because, future, developers, can, easily, add, another, dependency, as, needed);
 
[)roi(];18871776 said:
The usefulness of abstraction is always going to be tough nut to crack and appreciate. Dealing with generics (polymorphism) is always a bit of a fight; why we do it should ultimately become more clear over time; it's certainly not just to avoid code duplication, but more importantly is there to make our code structures more versatile.

And THAT is the reason why I lost one of my biggest contracts a year ago. The IT director of the client couldn't make heads or tails out of the lib I wrote which my team used in roughly 40 small projects. It was "plagued" by interfaces and generics and was written in Java.

My current go-to lib is done in C# and is again built on interfaces and generics. At least my team know how to effectively use it to maximum effect. I read last night that TypeScript now supports generics, which is something I'm excited to explore in January.
 
[)roi(];18871776 said:
The usefulness of abstraction is always going to be tough nut to crack and appreciate. Dealing with generics (polymorphism) is always a bit of a fight; why we do it should ultimately become more clear over time; it's certainly not just to avoid code duplication, but more importantly is there to make our code structures more versatile.

Found this post very encouraging. It has been and still is a bit of a fight with quite a road ahead of me but I'm determined as hell to crack that nut. Polymorphism, abstraction etc is like the brick wall that I'm sure has stopped many an aspiring coder dead in their tracks.

Continuing to practice with Interfaces and using all the advice I can in this thread. This is an ongoing thing atm.
 
Found this post very encouraging. It has been and still is a bit of a fight with quite a road ahead of me but I'm determined as hell to crack that nut. Polymorphism, abstraction etc is like the brick wall that I'm sure has stopped many an aspiring coder dead in their tracks.

Continuing to practice with Interfaces and using all the advice I can in this thread. This is an ongoing thing atm.
I'm wrapping up another DI example for you; a basic framework for a drawing app; barring wine delays, it should be up in the next hour or so.
 
Simplified example of a 2D Drawing Application framework, that could be used on Windows, Android, IOS, ...

The part in this example that requires specific OS adaptation is all the classes that adopt the Renderer interface, namely:
  • public class TestRenderer : IRenderer
  • public class WindowsRenderer : IRenderer
  • public class AndroidRenderer : IRenderer
  • public class IOSRenderer : IRenderer
Basically each of these classes need to provide a targeted OS implementation for the IRenderer methods:
  • MoveTo,
  • AddLineTo,
  • AddArc
These methods represent the primary draw methods for your diagramming application. From these basic shape methods we can create more complex shapes: Circle, Triangle, ... for example:
  • Circle is a method call to AddArc with a specific angle from 0 to 2 x PI
  • Triangle uses Polygon, but is the culmination of 3 AddLineTo method calls
  • Similarly Rectangle would use Polygon, and be the culmination of 4 AddLineTo method calls
  • etc...

The code is expressly simplified; an actual drawing application would required a lot more functionality.

PHP:
using System;
using System.Collections.Generic;
using System.Drawing;

namespace Draw
{
  public interface IRenderer
  {
    void MoveTo(PointF position);
    void AddLineTo(PointF position);
    void AddArc(PointF center, float radius, float startAngle, float endAngle);
  }

  public interface IDrawable
  {
    void Draw(IRenderer renderer);
  }

  public class Polygon : IDrawable
  {
    private List<PointF> corners = new List<PointF>();

    public Polygon(List<PointF> corners)
    {
      this.corners = corners;
    }

    public void Draw(IRenderer renderer)
    {
      renderer.MoveTo(corners[corners.Count - 1]);
      corners.ForEach(c => renderer.AddLineTo(c));
    }
  }

  public class Circle : IDrawable
  {
    private static float twoPI = (float)(Math.PI * 2);
    private PointF center;
    private float radius;

    public Circle(PointF center, float radius)
    {
      this.center = center;
      this.radius = radius;
    }

    public void Draw(IRenderer renderer)
    {
      renderer.AddArc(center, radius, 0F, twoPI);
    }
  }

  public class Diagram : IDrawable
  {
    private List<IDrawable> elements = new List<IDrawable>();

    public Diagram(List<IDrawable> elements)
    {
      this.elements = elements;
    }

    public void Draw(IRenderer renderer)
    {
      elements.ForEach(e => e.Draw(renderer));
    }

    public void add(IDrawable element)
    {
      this.elements.Add(element);
    }
  }

  /// <summary>
  /// Mocking Renderer for output to Console & Testing
  /// </summary>
  public class TestRenderer : IRenderer
  {
    public void MoveTo(PointF position)
    {
      Console.WriteLine("MoveTo: ({0})", position);
    }

    public void AddLineTo(PointF position)
    {
      Console.WriteLine("AddLineTo: ({0})", position);
    }

    public void AddArc(PointF center, float radius, float startAngle, float endAngle)
    {
      Console.WriteLine("AddArc: (center: {0}, radius: {1}, startAngle: {2}, endAngle: {3})", center, radius, startAngle, endAngle);
    }
  }

  /// <summary>
  /// Windows renderer.
  /// Adapted for System.Drawing.Drawing2D commands
  /// </summary>
  public class WindowsRenderer : IRenderer
  {
    public void MoveTo(PointF position) { }
    public void AddLineTo(PointF position) { }
    public void AddArc(PointF center, float radius, float startAngle, float endAngle) { }
  }

  /// <summary>
  /// Xamarin Android renderer.
  /// Adapted for Android.Graphics.Canvas commands
  /// </summary>
  public class AndroidRenderer : IRenderer
  {
    public void MoveTo(PointF position) { }
    public void AddLineTo(PointF position) { }
    public void AddArc(PointF center, float radius, float startAngle, float endAngle) { }
  }

  /// <summary>
  /// Xamarin IOS renderer.
  /// Adapted for CoreGraphics commands
  /// </summary>
  public class IOSRenderer : IRenderer
  {
    public void MoveTo(PointF position) { }
    public void AddLineTo(PointF position) { }
    public void AddArc(PointF center, float radius, float startAngle, float endAngle) { }
  }


  class MainClass
  {
    public static void Main(string[] args)
    {
      Circle circle = new Circle(new PointF(187.5F, 333.5F), 93.75F);
      Polygon triangle = new Polygon(new List<PointF>(new PointF[]{
        new PointF(187.5F, 427.25F),
        new PointF(268.69F, 286.625F),
        new PointF(106.31F, 286.625F)}));

      Diagram diagram = new Diagram(new List<IDrawable>(new IDrawable[] { circle, triangle }));

      // Renders console statement output for testing
      diagram.Draw(new TestRenderer()); 

      // Example of OS specific renderers

      // Renders Windows Diagram
      diagram.Draw(new WindowsRenderer()); 

      // Renders Android Diagram
      diagram.Draw(new AndroidRenderer()); 

      // Renders IOS Diagram
      diagram.Draw(new IOSRenderer()); 
    }
  }
}

The console output from this is :
Code:
AddArc: (center: {X=187,5, Y=333,5}, radius: 93,75, startAngle: 0, endAngle: 6,283185)
MoveTo: ({X=106,31, Y=286,625})
AddLineTo: ({X=187,5, Y=427,25})
AddLineTo: ({X=268,69, Y=286,625})
AddLineTo: ({X=106,31, Y=286,625})

The DI part btw is a IRenderer class that is passed in as a parameter to diagram.Draw method. i.e. parametric Polymorphism.

Note: I've specifically left incomplete the rendering implementations because that level of detail is not pertinent to the Interfaces and DI usage in this example. For interest sake though; here's an example of what these commands would have drawn:
Screen Shot 2016-12-22 at 8.48.33 PM.png
 
Last edited:
And THAT is the reason why I lost one of my biggest contracts a year ago. The IT director of the client couldn't make heads or tails out of the lib I wrote which my team used in roughly 40 small projects. It was "plagued" by interfaces and generics and was written in Java.

My current go-to lib is done in C# and is again built on interfaces and generics. At least my team know how to effectively use it to maximum effect. I read last night that TypeScript now supports generics, which is something I'm excited to explore in January.

Nothing special. If you're familiar with generics in .NET (or templates in C++), you'll feel (mostly) right at home. The only problem is when TS compiles (transpiles?) to JS, you lose all the strongly typed information, thus you have to write your own type checking as part of your classes.

(I'm currently experimenting with TS, whilst on leave.)

Code:
/**
 * A standard node for a binary search tree.
 * 
 * @class TreeNode
 */
class TreeNode<TKey, TValue> {
    private _key: TKey;
    private _value: TValue;
    private _parentNode: TreeNode<TKey, TValue>;
    private _leftChildNode: TreeNode<TKey, TValue>;
    private _rightChildNode: TreeNode<TKey, TValue>;

    /**
     * Creates an instance of TreeNode.
     * 
     * @param {*} Key
     * @param {*} Value
     * 
     * @memberOf TreeNode
     */
    constructor(Key: TKey, Value: TValue) {
        this.Key = Key;
        this.Value = Value;
		this.ParentNode = null;
		this.LeftChildNode = null;
		this.RightChildNode = null;
    }

	public get Key(): TKey {
		return this._key;
	}

	public set Key(Value: TKey) {
		this._key = Value;
	}

	public get Value(): TValue {
		return this._value;
	}

	public set Value(Value: TValue) {
		this._value = Value;
	}

	public get ParentNode(): TreeNode<TKey, TValue> {
		return this._parentNode;
	}

	public set ParentNode(Value: TreeNode<TKey, TValue>) {
		this._parentNode = Value;
	}

	public get LeftChildNode(): TreeNode<TKey, TValue> {
		return this._leftChildNode;
	}

	public set LeftChildNode(Value: TreeNode<TKey, TValue>) {
		this._leftChildNode = Value;
	}

	public get RightChildNode(): TreeNode<TKey, TValue> {
		return this._rightChildNode;
	}

	public set RightChildNode(Value: TreeNode<TKey, TValue>) {
		this._rightChildNode = Value;
	}
 
Last edited:
Nothing special. If you're familiar with generics in .NET (or templates in C++), you'll feel (mostly) right at home. The only problem is when TS compiles (transpiles?) to JS, you lose all the strongly typed information, thus you have to write your own type checking as part of your classes.

(I'm currently experimenting with TS, whilst on leave.)

Code:
/**
 * A simple implementation of a node for a binary search tree.
 * 
 * @class Node
 * @template TKey
 * @template TValue
 */
class Node<TKey, TValue> {
    private _key: TKey;
    private _value: TValue;
    private _right: Node<TKey, TValue> | null;
    private _left: Node<TKey, TValue> | null;

    /**
     * Creates an instance of Node, for a Binary Search Tree.
     * 
     * @param {TKey} key
     * @param {TValue} value
     * 
     * @memberOf Node
     */
    constructor(key: TKey, value: TValue) {
        this.Key = key;
        this.Value = value;
        this.Left = null;
        this.Right = null;
    }

public get Key(): TKey {
return this._key;
}

public set Key(value: TKey) {
this._key = value;
}

public get Value(): TValue {
return this._value;
}

public set Value(value: TValue) {
this._value = value;
}

public get Right(): Node  {
return this._right;
}

public set Right(value: Node | null) {
this._right = value;
}

public get Left(): Node  {
return this._left;
}

public set Left(value: Node | null) {
this._left = value;
}
}

No generic type constraints available? That would help with compile-time error checking... Nevertheless, it does look very C#-ish. Colour me excited! Actually doesn't surprise me all that much, seeing as Anders Hejlsberg is behind both languages.
 
No generic type constraints available? That would help with compile-time error checking... Nevertheless, it does look very C#-ish. Colour me excited! Actually doesn't surprise me all that much, seeing as Anders Hejlsberg is behind both languages.

I assume you're talking about the where statement C# offers?

Code:
public class MyList<T> where T : Humans

If so, I haven't seen any reference to it in the code and documentation I've looked at.
 
1) Find yourself in a new job as a developer.
2) Find yourself stuck in a disgusting web of legacy code and applications spread out over 30 years and 5 different languages.
3) These app's all have to share and communicate data.
...
4) understand why interfaces are a gift from god
 
I assume you're talking about the where statement C# offers?

Code:
public class MyList<T> where T : Humans

If so, I haven't seen any reference to it in the code and documentation I've looked at.

Exactly like that yes. Both C# and Java have type constrains for generics, so it would only be logical that TypeScript has as well. I'll research it a bit more next month.
 
Exactly like that yes. Both C# and Java have type constrains for generics, so it would only be logical that TypeScript has as well. I'll research it a bit more next month.

It supports constraints in the following sense;

Code:
Reach<T extends Around>
 
Nothing special. If you're familiar with generics in .NET (or templates in C++), you'll feel (mostly) right at home. The only problem is when TS compiles (transpiles?) to JS, you lose all the strongly typed information, thus you have to write your own type checking as part of your classes.

(I'm currently experimenting with TS, whilst on leave.)

Code:
/**
 * A standard node for a binary search tree.
 * 
 * @class TreeNode
 */
class TreeNode<TKey, TValue> {
    private _key: TKey;
    private _value: TValue;
    private _parentNode: TreeNode<TKey, TValue>;
    private _leftChildNode: TreeNode<TKey, TValue>;
    private _rightChildNode: TreeNode<TKey, TValue>;

    /**
     * Creates an instance of TreeNode.
     * 
     * @param {*} Key
     * @param {*} Value
     * 
     * @memberOf TreeNode
     */
    constructor(Key: TKey, Value: TValue) {
        this.Key = Key;
        this.Value = Value;
		this.ParentNode = null;
		this.LeftChildNode = null;
		this.RightChildNode = null;
    }

	public get Key(): TKey {
		return this._key;
	}

	public set Key(Value: TKey) {
		this._key = Value;
	}

	public get Value(): TValue {
		return this._value;
	}

	public set Value(Value: TValue) {
		this._value = Value;
	}

	public get ParentNode(): TreeNode<TKey, TValue> {
		return this._parentNode;
	}

	public set ParentNode(Value: TreeNode<TKey, TValue>) {
		this._parentNode = Value;
	}

	public get LeftChildNode(): TreeNode<TKey, TValue> {
		return this._leftChildNode;
	}

	public set LeftChildNode(Value: TreeNode<TKey, TValue>) {
		this._leftChildNode = Value;
	}

	public get RightChildNode(): TreeNode<TKey, TValue> {
		return this._rightChildNode;
	}

	public set RightChildNode(Value: TreeNode<TKey, TValue>) {
		this._rightChildNode = Value;
	}
Still very verbose; Is so much plumbing (constructor, getter/setter, ...) really required?
Is there no sugar syntax for getter / setters, or even the notion of a default constructor?

You can easily do better in F#, Swift, Rust, ..., Haskell with recursive discriminated union types. I quickly looked over the TypeScript documentations, and they do have the notion of a Union Type but like C# it appears very limited; pity.

As an example, here's the base definition of a BST in F# using a discriminated union type:
PHP:
type 'a Tree = Empty | Branch of 'a * 'a Tree * 'a Tree
Which basically says a Tree of type 'a' consists of either an Empty node, or a Branch containing one value of type 'a' with exactly two subtrees of type 'a'.

Similarly in Swift Union types have been rolled into Enums:
PHP:
public enum BST<T: Comparable> {
  case Empty
  case Leaf(T)
  indirect case Node(BST, T, BST)
}
Both types are recursive re the indirection of types 'a and BST. Hence I said TypeScript looks awfully verbose for a new language.
 
It supports constraints in the following sense;

Code:
Reach<T extends Around>

Ah, very Java-like then. Just another question: Does TypeScript have type erasure like Java? I'm guessing not, due to the loosely typed nature of JavaScript.
 
[)roi(];18880514 said:
Still very verbose; Is so much plumbing (constructor, getter/setter, ...) really required?
Is there no sugar syntax for getter / setters, or even the notion of a default constructor?

You can easily do better in F#, Swift, Rust, ..., Haskell with recursive discriminated union types. I quickly looked over the TypeScript documentations, and they do have the notion of a Union Type but like C# it appears very limited; pity.

As an example, here's the base definition of a BST in F# using a discriminated union type:
PHP:
type 'a Tree = Empty | Branch of 'a * 'a Tree * 'a Tree
Which basically says a Tree of type 'a' consists of either an Empty node, or a Branch containing one value of type 'a' with exactly two subtrees of type 'a'.

Similarly in Swift Union types have been rolled into Enums:
PHP:
public enum BST<T: Comparable> {
  case Empty
  case Leaf(T)
  indirect case Node(BST, T, BST)
}
Both types are recursive re the indirection of types 'a and BST. Hence I said TypeScript looks awfully verbose for a new language.

Re: the plumbing

A constructor is required, and only one constructor allowed per class, if you class is a derived class you need to make a super() call in that classes constructor.

Example:

PHP:
class A {
	public char: string;

	constructor(c: string) {
		this.char = c;
	}
}

class B extends A {
	public num: number;

	constructor(c: string, n: number) {
		super(c);
		this.num = n;
	}
}

Re: the accessors

Nope, not necessary. You can access the fields directly if you so wish. If you log an object that contains accessors to the console, it'll show you both the read accessor (get) and the field's value simultaneously.

Re: a new language

I wouldn't call it a new language per se. The idea behind it, is to give .NET developers the ability to code in JS without having to learn JS. (My interpretation any way)

The thing is, when TS compiles to JS, you lose all strongly typed information.
 
Last edited:
Re: the plumbing

A constructor is required, and only one constructor allowed per class, if you class is a derived class you need to make a super() call in that classes constructor.

Example:

PHP:
class A {
	public char: string;

	constructor(c: string) {
		this.char = c;
	}
}

class B extends A {
	public num: number;

	constructor(c: string, n: number) {
		super(c);
		this.num = n;
	}
}

Re: the accessors

Nope, not necessary. You can access the fields directly if you so wish. If you log an object that contains accessors to the console, it'll show you both the read accessor (get) and the field's value simultaneously.

Re: a new language

I wouldn't call it a new language per se. The idea behind it, is to give .NET developers the ability to code in JS without having to learn JS. (My interpretation any way)

The thing is, when TS compiles to JS, you lose all strongly typed information.
Ta... Guess the end conclusion (at least for me); it's impossible to be hitched to something broken and fix it from outside. Also did a quick review of TS; the language is lacking overall, even compare to JS; certainly don't see the point in this.
 
[)roi(];18882018 said:
Ta... Guess the end conclusion (at least for me); it's impossible to be hitched to something broken and fix it from outside. Also did a quick review of TS; the language is lacking overall, even compare to JS; certainly don't see the point in this.

It's to provide type safety in JavaScript where type / error checking can be done compile-time, pre-ES6.
 
Top
Sign up to the MyBroadband newsletter
X