Interfaces vs Abstract Classes

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,826
#41
I covered Trampolines in this post; not to the full extent of what I explain, but this example, does cover standard recursion using trampolines (Sorry code is in Swift) https://mybroadband.co.za/vb/showth...Challenges?p=18749328&viewfull=1#post18749328

/Edit what I failed to mention is that with this type of approach the function arity is usually kept to a minimum: 1 value in, 1 value out -- because the typing of this can get complex rather quickly. This is also where currying and partial application simplify things a lot.

PS. C# 7 is introducing both tuples and pattern matching so most of the Swift code should easily translate. Although it's certainly quite possible to do that with C# 6, maybe just not as elegant.
 
Last edited:

zippy

Executive Member
Joined
May 31, 2005
Messages
9,643
#42
A good explanation of Java interfaces and abstract classes is on the old Shape class example. You would have an abstract class called Shape. You then have an interface called Drawable. In the Drawable interface you have a method called draw. You then create classes which extend Shape and implement Drawable. So an instance of a Circle class which extends Shape and implements Drawable will have its way of drawing based on PI etc, whereas an instance of Rectangle would have a different way.

An application which uses these Shapes can then be written by drawing all of the circles and rectangles by calling calling the draw method on an array of Shapes. The Shapes will be correctly drawn based on the sub classes implementation.

Why do this? Well you can add other shapes and you don't need to change the code that in the app draws the objects. If they are sub classed from Shape they will be drawn as long as they are the in the array of objects(hint : annotations and injection)

Why separate Drawable in an interface? Drawable can implemented by other classes, not just Shapes.

Inheritance can be overdone. That doesn't mean it's a bad thing. It means the developer doesn't understand it.
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,826
#44
Last edited:

Spacerat

Senior Member
Joined
Jul 29, 2015
Messages
813
#48
using an abstract base class still binds you to that class. If the class adds no value, why have it at all? whereas an interface defines the contract between the implementation and consumer and do not force you to use any base class. Read up on the L in SOLID. Liskov's substitution principle
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,826
#49
As for DI that's arguably OOP's solution to the lack of currying and partial application, whereas SOLID is arguably an attempt to make OOP more like Functional Programming; because each of its tenets are innate to FP, for example:
  • Single-responsibility Principle:
    FP's unit of abstraction is a function; with a single input & output; a natural single responsibility.
  • Open/Closed Principle:
    Functions are easily substituted, extensibility is innate and instead of having to bother with virtual methods or inheritance, we can simply rely on higher order functions.
  • Liskov Substitution Principle:
    With FP this is trivial; it favors parametric polymorphism without sacrificing safety, avoids inheritance issues, substitution is innate and composition is reusability.
  • Interface Segregation Principle:
    FP removes any need for encapsulation by deliberately avoiding state, composition is a core tenet and Interfaces aren't required; because both the role of a function and it's segregation is explicit.
  • Dependency Inversion Principle:
    FP being both declarative and side effect free, is a natural inversion of dependency.
 
Last edited:

XennoX

Expert Member
Joined
Nov 15, 2007
Messages
2,204
#50
@Droid, when you mention the aspect of Dependency Inversion, are you referring to the design pattern of Inversion of Control?
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,826
#51
@Droid, when you mention the aspect of Dependency Inversion, are you referring to the design pattern of Inversion of Control?
Dependency inversion is the SOLID design principle, namely:
  • High level modules must not directly depend on low level ones; they both should depend on abstractions.
  • ...and Abstractions shouldn't depend upon details, inversely details should depend on abstractions.
Inversion of control as you correctly posited is an OOP mechanism to do this i.e. to make the higher level modules depend on abstractions rather than concrete implementations of lower level modules. Also the combination of DI and IoC is what's typically employed to comply with this SOLID principle.

In FP: The natural declarative and side-effect free approach of FP provides dependency inversion as a default; side-effects are more naturally triggered in response to domain behavior as opposed to being directly invoked by domain behavior. So dependencies don't just become inverted, but tend to be pushed to outer layers; and "details should depend on abstractions" is the default approach with functors (single process acting on data), and applicatives (multiples processes acting on data)
 
Last edited:

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
17,825
#52
I had the "penny drop" moment.

Taking the Pizza Class example, you could create an interface IPizza and use that throughout all your classes to ensure that classes like PepperoniPizza and HawaiiPizza adhere to ALL of the methods and properties NECESSARY for any pizza class.

You could then create a IPepperoniPizza and IHawaiiPizza and each of those would do the same thing, be used to ensure that any pizza object of PepperoniPizza or HawaiiPizza adhere to specific methods and properties necessary for those classes.

In addition to that Interfaces can also inherit from other interfaces so, inside both IPepperoniPizza and IHawaiiPizza you could set a reference to IPizza for the same reason, to force them to stick to "the rules"

In addition to that if you wanted to create a Hybrid pizza of both Peperroni and Hawaii pizza's called HawaiiPeperoni, you would add a reference to both IPepperoniPizza and IHawaiiPizza to ensure that all of the required ingredients (properties) and cooking methods (functions) are adhered to.

That gets around the problem of Multiple Inheritence which C# cannot do.

Also using IPepperoniPizza you could use In or AS to check which pizzas are Pepperoni Pizzas

Code:
public PreparePizzas(IList<IPepperoniPizza> pizzas)
{
    foreach (IPepperoniPizza pizza in pizzas)
        pizza.Prepare();
}
When using and Abstract class as your base, there is still no guarantee that the user will stick to the rules aka that they will use all of the required properties or methods necessary to create lets say a PepperoniPizza. An interface will guarantee that ALL of the required methods or properties are used.
 
Last edited:

_kabal_

Expert Member
Joined
Oct 24, 2005
Messages
2,607
#53
Basically yes.

But you probably would not use an inheritance tree like your example, but rather use composition with something like "List<Ingredient>"

A pizza is a pizza. It's behavior doesn't really change depending on toppings.

Sticking with the analogy, you would probably create a "Pizza" class, which implements something like "IPreparable".
"Hamburger" could also then implement "IPreparable"

PHP:
class Kitchen {
    public PrepareItems(List<IPreparable> items) {
        foreach (IPreparableitem in items) {
            items.Prepare();
        }
    }
}
 
Last edited:

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
17,825
#54
Basically yes.

But you probably would not use an inheritance tree like you example, but rather use composition with something like "List<Ingredient>"

A pizza is a pizza. It's behavior doesn't really change depending on toppings.

You would probably create a "Pizza" class, which implements something like "IPreparable".
"Hamburger" could also then implement "IPreparable"

PHP:
class Kitchen {
    public PrepareItems(List<IPreparable> items) {
        foreach (IPreparableitem in items) {
            items.Prepare();
        }
    }
}
Thanks kabal. Still LOADS to chew over in this thread, got a wealth of information here. I'm only just scratching the surface.
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,826
#55
@solarion, you've touched on one of the reasons interfaces are great; the ability to write a function generically so that it can handle different values identically without depending on their underlying type (class).

This is btw called parametric polymorphism as is part of complying with the Liskov substitution principle.
 

semaphore

Honorary Master
Joined
Nov 13, 2007
Messages
10,149
#56
I personally find circle jerk over DI, think its the silver bullet to everything. Then implement is the worst possible way imaginable.
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
5,826
#57
I personally find circle jerk over DI, think its the silver bullet to everything. Then implement is the worst possible way imaginable.
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.
 
Joined
Sep 1, 2016
Messages
2,196
#58
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.
This, at the end of the day I guess the whole effort is to reach the goal of code that is simple, and works well.
 
Joined
Sep 1, 2016
Messages
2,196
#60
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.
 
Top