Interfaces vs Abstract Classes

skimread

Executive Member
Joined
Oct 18, 2010
Messages
8,545
I think that might confuse him more tbh. He's learning the basics and I think you need to understand interfaces to understand dependency injection.
Interfaces have a couple of benefits. If you only look at one then you might think it its too much effort for what it's worth. If you look at the other benefits it gives the full picture for you to see its worth

e.g.
- You can inject another object that implements that same interface for unit testing. So for testing instead of using a database repository object/ web service you can inject your own dummy object that implements that returns dummy data
- It's very easy to pass objects around using its interface so if you change to a different object you don't have to change all the references e.g. lots of collection objects implement IEnumerable.
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,930
Thing is, a class can only extend a single abstract class but can implement multiple interfaces.
Exactly, interfaces are far better and more flexible. C# unfortunately still sucks re default interface methods and polymorphic typing. If they mirror more of F#; things will certainly become significantly easier; and I'm assuming copious amounts if syntactical sugar to reduce verbosity.

That's a C# limitation if I'm not mistaken. Personally I think inheritance should die and we should all just use composition.
Exactly, inheritance is completely irrelevant, and has been for a long time. Polymorphism has no bearing on this; far easier ways to implement polymorphic code.

Java supports faux multiple inheritance via default methods
That's a far better way than the old inheritance hogwash. Unfortunately due to Java's "generic" implementation; it's severely limited. Languages like Haskell, F#, Swift and Rust are far better examples of what can be done with this.
 
Last edited:

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
18,314
Read up up dependency injection and interfaces will make more sense
I think that might confuse him more tbh. He's learning the basics and I think you need to understand interfaces to understand dependency injection.
I have a DI book recommended to me from one of you guys. It's too advanced for my level atm so I've gone back to basics.

This example doesn't really show the reason why one would use an interface rather than an abstract class (as per thread title) - the same thing could be achieved extending an abstract class
That's where the confusion comes in for me, and after chewing over Interfaces all day it still all boils down to: Why not just use an abstract class?

Most sources/books/websites tell you how to use Interfaces, and when to implement them, but they don't tell you WHY.

Edit:

Just Found this. Page 272 of Head First C#

An interface requires that a class has certain methods, and the way that it does that is by making the compiler throw errors if it doesn’t find all the methods required by the interface in every class that implements it. Those methods can be coded directly in the class, or they can be inherited from a base class. The interface doesn’t care how the methods or properties get there, as long as they’re there when the code is compiled.
Page 274

Interfaces aren’t about preventing you from duplicating code. They’re about letting you use one class in more than one situation.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,930
If I get a free moment tomorrow; I'll post some DI code.

Is this just something you're learning, or is there a particular problem you're trying to solve. Reason I ask it to evaluate whether DI is the most appropriate solution for your need?

Occasionally connecting data & code can be helpful, but doing so always carries a cost. The need to pipeline data through a process is a common one for any paradigm, where it differs is in the implementation. You should also be aware that coupling data & code always adds an extra layer of complexity e.g. if you want to use something, you'll need an appropriate mechanism (like DI) to pass that object down the call path.

In contrast with Functional Programming (FP) we tend to think more about input & output; specifically the chaining of 1 function's output into the input of the next. This approach focuses more on the data dependencies and not so much the function and / or object dependencies; which also leads to easier testing; DI is certainly not easy when it comes to testing, and quite often involves mock objects. With FP dependencies are typically inverted, meaning there's usually no extra work if the design follows a more strictly pure and total function style approach. Further simplification (including sharing) is possible with Higher Order Functions, Partial Application and Lambda style closures for arguments.

In summary, you probably should to explore your options, for a more informed choice.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,930
As for Interfaces (also called Contracts, Protocols, ...) -- these define compliance. if a method parameter is tied to an iInterface, it is mandating that the calling process provide a compliant type for that parameter. Having this compliance means that the internal workings can be secure that the passed in reference will provide implementations matching those mandated by the Interface.

Interfaces allow for multiple trait scenarios, for example: a type can as example be constrained to both IComparable (e.g. Sort decriptor) and IEquatable (Data equality verification).

At it's most flexible it not only allows Interface to inherit other Interface but also for default method implementations, method & type overrides, generic type narrowing, etc.. Why do we need this? Simply said it substantially cuts out boilerplate and code duplication, e.g. 1 generic type constrained extension method per Interface vs. 1 per type.
 
Last edited:

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
18,314
[)roi(];18851412 said:
If I get a free moment tomorrow; I'll post some DI code.

Is this just something you're learning, or is there a particular problem you're trying to solve. Reason I ask it to evaluate whether DI is the most appropriate solution for your need?

Occasionally connecting data & code can be helpful, but doing so always carries a cost. The need to pipeline data through a process is a common one for any paradigm, where it differs is in the implementation. You should also be aware that coupling data & code always adds an extra layer of complexity e.g. if you want to use something, you'll need an appropriate mechanism (like DI) to pass that object down the call path.

In contrast with Functional Programming (FP) we tend to think more about input & output; specifically the chaing of 1 function's output into the input of the next. This approach focuses more on the data dependencies and not so much the function and / or object dependencies; which also leads to easier testing; DI is certainly not easy when it comes to testing, and quite often involves mock objects. With FP dependencies are typically inverted, meaning there's usually no extra work if the design follows a more strictly pure and total function style approach. Further simplification (including sharing) is possible with Higher Order Functions, Partial Application and Lambda style closures for arguments.

In summary, you probably should to explore your options, for a more informed choice.
It's something I'm learning. I've been going through this book Head First C# and this all came up in Chpt 7. Abstract classes, Inheritance, Encapsulation all of that I don't have a problem with. I think I may just shelve Interfaces for now and try to move on. Either that or I have reached the end of the road with regards to programming I think.



I think I'm more of a Functional programmer, or a learning one at that.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,930
It's something I'm learning. I've been going through this book Head First C# and this all came up in Chpt 7. Abstract classes, Inheritance, Encapsulation all of that I don't have a problem with. I think I may just shelve Interfaces for now and try to move on. Either that or I have reached the end of the road with regards to programming I think.



I think I'm more of a Functional programmer, or a learning one at that.
Ps. The concept of Inheritance in the traditional OOP sense of super classes is dead. The ideas behind this have been carried forward to Interfaces with allowance for multiple "inheritance"; in quotes because its not real inheritance, but rather a promise that your class will comply with the specification of the Interface (Contract).

Basically if the Interface has declared method abc; then by "inheriting" the Interface you will be expected to provide an implementation for method abc (with same signature) that does what it should within your class.

For example:
INoisable might have a method with the following signature:
  • void makeNoise() {}

A duck class "inheriting" this trait might make a quack sound for this method, whereas a dog class would bark. The difference between traditional inheritance is that it doesn't have the inheritance baggage of super classes (including unwanted features); your Interfaces typically are designed around the lowest common denominator.

As I said advanced implementations (which are coming to C#) allow default implementation for these methods meaning your class would be able to use the default implementation instead of implemting it's own; however where necessary you can override. This should sound alot like the typical child / parent inheritance model because it is, except it doesn't have any of the issues asscoiated with that.

Doubtful re the end of the road; any new paradigm shift is going to be difficult; ultimately time simplifies most things. As for Functional Programming; that's certainly my preference, although I still need to work on a lot of OOP code.

FP is a lot easier for new programmers. The ones who find it most daunting are the programmers that have been doing OOP for many years, because the shift in approach is so different. Happy to help you get started if that's where you interest lies.

Naturally learning FP in C# is still quite restrictive; not that you can't do a lot, you can; however a language like F# certainly is far more flexible as it has been ground up designed for FP; but even then you can program OOP in F# if you need to, similarly the default behavior is immutable types, but you can mutate anything by flagging it with the "mut" keyword. C# 7 is introducing a lot of really nice FP things e.g. Tuples, Pattern matching, ...

FP is however available in many languages; Java for example added a lot of really great stuff in version 8.
 
Last edited:

krycor

Honorary Master
Joined
Aug 4, 2005
Messages
14,784
As the last few posters infer.. in a classic sense it's multiple inheritance for java/c# but actually it's not, it's guaranteeing your object will comply with specs defined on how a particular use case is defined..

so to extend on what roi said.. certain anything animals will implement a 'Riding' so e.g. Horses, Elephants will implement, but do so differently and the implementation there of is with the class so neatly packaged.

(Typing on iPad, so brief but I hope it makes sense)
 

C4Cat

Executive Member
Joined
Nov 9, 2015
Messages
8,450
See if this makes sense: imagine you have an abstract class called Vehicle and you have a number of subclasses that extend it, say Car, Truck, Helicopter, Aeroplane, Bicycle and Scooter. Now you want to isolate all the Vehicles that can fly, call a method called getMaximimFlightHight in order to see which vehicle can fly the highest. It doesn't make sense to add the method to the abstract class Vehicle since not all vehicles fly but at the same time you want to guarantee that all vehicles that do fly have a method called getMaximimFlightHight. So you create an interface called FlyingThing which has the getMaximimFlightHight method signature. All the vehicles that fly (Aeroplane and Helicopter) implement this interface. This will guarantee the method is available in those classes... If you happen to have a class called Bird and one called Bee, both of which implement the FlyingThing interface, then you could even compare the flight hight of a Bee to an Aeroplane since you know both will have the maximum flight hight method even though one extends Vehicle and the other doesn't.
 

etienne_marais

Executive Member
Joined
Mar 16, 2008
Messages
6,522
It's something I'm learning. I've been going through this book Head First C# and this all came up in Chpt 7. Abstract classes, Inheritance, Encapsulation all of that I don't have a problem with. I think I may just shelve Interfaces for now and try to move on. Either that or I have reached the end of the road with regards to programming I think.

I think I'm more of a Functional programmer, or a learning one at that.
Don't shelve interfaces, try to use them instead and only use abstract classes / inheritance when it becomes desirable for the partial implementation it offers or when design patterns justifies the need.
 

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
18,314
Alright, have the rest of the day free now. Time to sit down with some coffee and read over you guys' posts. This is why I love mybroadband programming community. Often I've been on the brink of giving up but your patience in explaining things is second to none.
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,930
As promised, a simple example of Dependency Injection

Note: I'm using the PHP code tags simply to add colour; the code is C#

We're going to start with a simple Employee class, that we instantiate for the employee "Jack Taylor"
PHP:
using System;

public class Employee
{
  public string firstname { get; }
  public string surname { get; }

  public Employee(string firstname, string surname)
  {
    this.firstname = firstname;
    this.surname = surname;
  }
}

 namespace DI
{
  class MainClass
  {
    public static void Main(string[] args)
    {
      Employee employee1 = new Employee("Jack", "Taylor");
    }
  }
}
Then after a while we realise we need to some type of logging mechanism to track what is going on within our code, so we alter the class to add a toLog() method. Which we then can call whenever we want to log employee data to the console.

PHP:
public class Employee
{
  public string firstname { get; }
  public string surname { get; }

  public Employee(string firstname, string surname)
  {
    this.firstname = firstname;
    this.surname = surname;
  }

  public void toLog()
  {
    string output = string.Format("[firstname: {0}, surname: {1}]", this.firstname, this.surname);
    Console.WriteLine("{0:yyyy-M-d dddd hh:hh:mm:ss tt zz} : {1}", DateTime.Now, output);
  }
}

namespace DI
{
  class MainClass
  {
    public static void Main(string[] args)
    {
      Employee employee1 = new Employee("Jack", "Taylor", new LoggerTest());
      employee1.toLog();
    }
  }
}
Now our codebase starts growing and we keep adding this toLog() method to every new class we create; so no problem, well that is until some bright spark pipes up and says:
  • Let's change the format of the log output to include .......
  • or.... let's log this in production to a dedicated logging server, and in testing to the console.
Whew at which point you're probably doing your nut, because you've just realised there are over 100s of classes that have a toLog() method.

Question: So how could we have avoided this pain? This is a good (and simple) example of where Dependency Injection techniques can help.

Dependency Injection
First off we need to define our generic requirements for logging; remember we're not at this point in time concerned about the how, but rather the what we need. Why, simply because as the above example showed, some bright spark will always come up with some new way to do the logging, and your code structure will need to be flexible enough to handle those changes.

Interfaces
We going to define our logging requirement using an interface, because as I said we're less interested in how the logging is done, and more interested in what it needs to do. Interfaces are perfect for that.
PHP:
public interface ILog
{
  void WriteToLog(String text);
}
Ok, that's quite short and sweet; we've created a ILog interface which specifies that any class adopting this Interface must create a void method called WriteLog with a single String parameter text.

So how do we use this?
Let's start by rewriting our employee class to use this interface.
PHP:
public class Employee
{
  public string firstname { get; }
  public string surname { get; }
  private ILog log;

  public Employee(string firstname, string surname, ILog log)
  {
    this.firstname = firstname;
    this.surname = surname;
    this.log = log;
  }

  public void toLog()
  {
    string output = string.Format("[firstname: {0}, surname: {1}]", this.firstname, this.surname);
    this.log.WriteToLog(output);
  }
}
As you can see we've added another property called log which is of type ILog; the interface we just defined. Similarly we added another parameter to our default Constructor, expecting anyone who instantiates employees to provide a class that adheres to ILog (i.e. a class that has a "void WriteToLog(String text)" method)

Next you can see in the toLog() in the employee class, we are now calling that method "this.log.WriteToLog(output);" as opposed to writing the output directly to the console.

Now let's create a class that complies to the ILog interface and just writes output to the Console?
Basically we're going to create a class that does exactly what the "Console.Writeline..." was doing previously.
PHP:
public class LogConsole : ILog
{
  public void WriteToLog(string text)
  {
    Console.WriteLine("{0:yyyy-M-d dddd hh:hh:mm:ss tt zz} : {1}", DateTime.Now, text);
  }
}

namespace DI
{
  class MainClass
  {
    public static void Main(string[] args)
    {
      Employee employee1 = new Employee("Jack", "Taylor", new LoggerConsole());
      employee1.toLog();
    }
  }
}
As you can see it's a pretty simple class that adds conformance to an interface "public class LogConsole : ILog", internally in accordance with interface contract it provides an implementation matching the "public void WriteToLog(string text)", except that it now includes the how part i.e. writing this out to the console.

Then in the Main method when we instantiate the employee "Jack" we are now required to provide an object that adheres to the ILog interface, the result is exactly the same; same commands, same output.

Now let's look at a scenario where we want differentiate actions between testing and production. Simple we create two classes that adhere to ILog interface, namely LoggerProduction and LoggerTest.
PHP:
public class LoggerProduction : ILog
{
  public void WriteToLog(string text)
  {
    Console.WriteLine("{0:yyyy-M-d dddd hh:hh:mm:ss tt zz} : {1}", DateTime.Now, text);
  }
}

public class LoggerTest : ILog
{
  public void WriteToLog(string text)
  {
    Console.WriteLine("{0} : {1}", "** Testing " + new string('*', text.Length - 9), text);
  }
}
As you can see the how part varies slightly between LoggerProduction and LoggerTest. Using this is quite easy, as we simply have to provide the correct one when we instantiate the employee instance, for example:
PHP:
namespace DI
{
  class MainClass
  {
    public static void Main(string[] args)
    {
      Employee employee1 = new Employee("Jack", "Taylor", new LoggerTest());
      employee1.toLog(); // This writes using the LoggerTest write to log method

      Employee employee2 = new Employee("Jack", "Taylor", new LoggerProduction());
      employee2.toLog(); // This writes using the LoggerProduction write to log method
    }
  }
}
Easy enough ???

Naturally you also wouldn't want to have to change every instantiation line of code every time you switch between production, test, and other loggers. i.e. to avoid that you could define a global instance variable for logging, for example: a singleton, or just chain the instance through to the point where you need.

That global instance variable would then probably have some compiler logic allowing you to specify whether you're testing or running in production i.e. automatic adaption.

...and when the bright spark encourages the manager to do something else, you'll easily be able to accomplish it by simply creating a new class implementation that conforms to the ILog interface.

Anyway hope that helps.
 
Last edited:

etienne_marais

Executive Member
Joined
Mar 16, 2008
Messages
6,522
A nice 'side effect' of DI as well as Visitor design pattern in larger projects, in C#, is that only one assembly needs to be recompiled (where the new / altered functionality is implemented) and the consuming sections may be in existing libraries / dll's perhaps written by a different developer with the source not readily available.
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,930
Intermediate comment:
The next ~related aspect of dependencies is inversion (namely: Dependency Inversion); a technique for loosely coupling of classes i.e.:
  • High level module extraction to avoid low level dependencies; in short both typically depend on abstractions.
  • ...and similarly the abstractions shouldn't depend on the details; quite the opposite details should depend upon abstractions.
Ling makes this easy with Higher Order Functions, but you can design it similar to Dependency Injection using your own Higher Order Method / Interfaces.

Advanced comment:
Taking this a step further is trampolining techniques, which essentially is a loop that iteratively invokes functions (that return a value; a thunk) in a similar style to recursion; however this continuation style of programming enables you to take this a step further, beyond recursion of a single function; to the point of method chaining, and an easier transition to lazy evaluation (if required).
 

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
18,314
Thing is Roi, I'm inclined to just scrap the LogConsole class, and the ILog interface and just put the logger straight into the Employee class. I'm likely missing something because I look at it all and don't see the point.

My personality type is, I'll reach for the hammer and just make it work.
 

C4Cat

Executive Member
Joined
Nov 9, 2015
Messages
8,450
Thing is Roi, I'm inclined to just scrap the LogConsole class, and the ILog interface and just put the logger straight into the Employee class. I'm likely missing something because I look at it all and don't see the point.

My personality type is, I'll reach for the hammer and just make it work.
Did my previous post make any sense to you? Just curious
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,930
Thing is Roi, I'm inclined to just scrap the LogConsole class, and the ILog interface and just put the logger straight into the Employee class. I'm likely missing something because I look at it all and don't see the point.

My personality type is, I'll reach for the hammer and just make it work.
In your approach consider having e.g. 100+ classes; would you really want to duplicate logging code throughout all of these? and then imagine being requested to make a change to the logging; it would mean you would have to revisit all 100+ classes to make that change.

DI is something that always is going to look (to a beginner) like a lot of unnecessary complexity for no gain; the gain is in avoiding the pain both down the line, and in e.g. mocking up your tests without having to replicate the whole of the production environment for unit testing. This also was a simplistic DI example; real situations are far more complex.

/Edit Some might even advise using a singleton class for logging as opposed to DI -- maybe?? but that again comes down to experience and scenario; Singletons in general are well known for their difficulty to test, and you certainly wouldn't want to hang your entire app on what essentially is global state.

Side note: Also this is the OOP way to solve this problem; in Functional Programming the solutions are far more terse, and the approach (scenario depending) would typically use some combination of currying, partial application, higher order functions, etc. Basically what OOP does in DI is built in for most functional programming (part of the syntax); it's just a matter of knowing how to use it.
 
Last edited:
Top