Interfaces and abstract classes: it’s all about the inheritance

! Warning: this post hasn't been updated in over three years and so may contain out of date information.

This article started out as a “Should we scrap interfaces?” follow up to my previous “Did we get OO Interfaces all wrong?” article. I have been struggling with interfaces for some time now as they just don’t seem right to me. They are useful, I’d not dispute that; and they enhance OO languages, especially those that lack multiple inheritance. They just strike me as a case of semantic salt, ie the computer language semantic equivalent of syntactic salt.

Instead of risking writing another “flame bait” post though, I’ve decided to take a different tack by trying to understand the opposite view to my own. With that in mind, consider the following two code snippets:

Question: What is the difference between IMathOperation and MathOperation?

To my mind the answer is clear: for most OO languages, if my class PlusOperation provides an implementation of IMathOperation, it is still free to inherit from some other class, whereas if it provides an implementation of MathOperation it can’t. This answer is of course based on the idea that most OO languages do not allow multiple inheritance.

In other words, there is no difference between them save that the interface dodges the ban on multiple inheritance, whereas the abstract class doesn’t.

Now I have quite deliberately talked of implementing MathOperation and inheriting from IMathOperation, for to my mind the two terms are semantically identical with respect to these examples, save for the multiple inheritance issue.

This claim – that they are the same – seems to upset some people and they insist they are very different things. So I have a challenge for those people. Imagine there exists a language – called Lapsan of course – which permits a special case of multiple inheritance. As MathOperation has no explicit constructor; defines no fields; defines no concrete properties (as in getters/ setters; not member variables) or methods and doesn’t inherit from a class that does, Lapsan allows MathOperation to inherit both from MathOperation and another class. The Lapsan compiler in fact compiles MathOperation and IMathOperation to identical bytecode, for they are semantically identical.

If anyone feels that MathOperation and IMathOperation are still different and that the former is inherited, whilst the latter provides a contract or service, I’d love you to explain why. If you accept they are the same with Lapsan, but see the same code in say Java or C# as the former is inherited whilst the latter provides a contract or service, I’d also love you to explain why.

Silence will be taken as a sign that those doubters now accept I was right all along πŸ™‚

21 thoughts on “Interfaces and abstract classes: it’s all about the inheritance

  1. Thought provoking!

    But…

    I don’t think even hardcore interface fans would advocate an interface for a utility function/class such as your MathOperation.

    Where interfaces come in to their own is when you design by composition instead of inheritance.

    Even more importantly, if my code is compiled in chunks (modular) then if my modules have to contain actual classes rather than just interfaces (for the parts from other modules they use) then when I edit the implementation of those classes I have to also recompile the modules that use them.

    Scale that down, and when you and I are working on different parts of the project, but our code crosses over, we need to constantly keep each other updated of changes to the concrete code… where as if we’re working to interfaces then we only need to keep the API stable.

    Finally… speaking as someone who works on an open source framework … if you want to be able to have people create extensions and utilities that work with all your 1.x.y versions, for example, you have to have them build to the interfaces not the concrete instances. Otherwise you need a version of every utility for 1.0.1, 1.0.2 yada yada.

    Assuming you observe semantic versioning and your API (interfaces) are backward compatible, you can build a single version that works across the board.

    Interfaces are useful promises in the same way as – for example – standard sizes on lightbulbs. If I know I need a K23 lightbulb, I can switch in any K23 lightbulb – it can be pink, green, energy saving, long life, made by any manufacturer.

    So – I see interfaces as ‘standards’ sets. The K23 standard is *not* the same thing as a specific K23 lightbulb. The ISO-whatever fuel standard that guarantees that your car won’t choke is not the same as the gallon of fuel that obeys it.

    So – no, I think you were wrong all along ;P

    Maybe I see this from a different perspective because I started out in real-world engineering, and I know the difference that standardisation (Design-to-contract) has made to consumers and builders in the physical world.

  2. I agree with @Stray and would even go a step further. Not merely identifying an object as “adhering to a standard”, you can also see interfaces as ‘roles’ of an object, that give an uncluttered overview of the tasks that an object can do. One object may implement several interfaces at once. For example, a model class might implement one interface that allows read/write access, and another that allows read-only access, but they still belong in one class because they use the same service or backing store. By talking to that object through it’s interfaces, you can keep your roles separate, clarifying code and purpose of what kind of operations you’re executing.

  3. @Stray,

    Thanks for sharing your thoughts. The only problem though is that they do not seem to address the point I was trying to make: that there is no semantic difference between a completely abstract class and an interface, save for multiple inheritance restrictions.

  4. There may be no practical difference between your 2 examples – but semantically (in the original sense of semantics – the study of meaning) they are utterly different. They *mean* different things.

    Did you actually mean ‘semantically’?

    It is for semantic reasons that I argue that they are so different. The ‘idea’ of what a cat, or lightbulb, or tee shirt, is *not* the same as even the most empty or basic or plain version of an actual cat/lightbulb/tee shirt.

    I’d go further – inheritance implies the ‘is-a’ relationship. This is the purest semantic conclusion we can draw from an inheritance chain – that the super-type-sub-type relationship is one of generality and speciality.

    Interfaces only imply an ability or suitability or common characteristic. For example, things with pockets – which would include car seats, clothing, back packs. Nobody would argue that these share a base type beyond ‘objects’. Yet getPocketContents() would be valid in all these cases.

  5. See http://en.wikipedia.org/wiki/Semantics#Programming_languages for what I mean by semantics. The syntax of the code is different for the interface and abstract class, but if they end up compiled to the same bytecode, they mean the same thing and so are semantically identical.

    Is AS3, we can do things like if (obj is IFoo) { ..., for the “is a” relationship makes sense for interfaces as well as classes. Abstract classes are ideas, contracts, call them what you like, just like interfaces.

    Using your example of pockets, take the following code:

    Here we are using an abstract class to cover “thing with pockets”, regardless of what that thing might be. One normally uses interfaces in this situation only because of multiple inheritance restrictions. Without those restrictions, the choice of abstract class or interface becomes one of syntactic preference only, for semantically they are the same thing..

  6. I, too, agree with Stray. And, Stray has already done a good job of discussing the benefits of interfaces. But, for some reason, my mind (currently) wants to focus on your use of the abstract class.

    Even if your claim was correct, I’m not sure what the purpose of it is. It seems that you’re basically saying that, if you take two things and strip them down as far as possible, then they’ll be exactly the same (apart from the differences).

    If you take two different classes and delete all of the properties and methods, then they’ll be exactly the same (apart from name & package).

    If you take a real life automobile and ….

    It seems that you intentionally left out the implementation capabilities of the abstract class. Inheritance is not the only difference between interfaces and abstract classes. The capability for abstract classes to provide common, default implementations is another very important difference. Even if you intentionally delete all of the existing implementation logic, for some reason, the abstract class still has that potential, where the interface does not.

    As Stray discusses, interfaces are standardization agreements … contracts. Abstract classes are unfinished-classes. The purpose and uses are different. Even if you delete everything and make them look as if they are the same, they are still different due to what they are capable of. Deleting everything to make them “appear” to be identical (whether we’re talking about interfaces, abstract classes, automobiles, buildings, DNA, etc.) seems to be an attempt to make an intentionally false comparison.

  7. You’ve kind of being hoisted by your own petard there: you want me to ignore the specifics of language (no multiple inheritance in AS3) for the point of your example, and yet you use the specific interpretation of the wishywashy ‘is’ operator from AS3 to support your argument that they’re the same?

    AFAIK, both C# and VB have a specific syntax for checking interfaces rather than subtypes.

    I personally consider it a big weakness that AS3 doesn’t have a different operator for testing extends vs implements. The ‘is’ operator in AS3 means ‘extends or implements’ – this no more implies that (extends == implements) than a = (b || c) would imply that b == c.

    [We’ll put aside here the fact that doing an ‘is’ check is a sign that your design is borked unless you’re building something that has to be both type-safe and generic such as the as3 signals or robotlegs libraries.]

    But, the crux of our difference is the choice of view point when interpreting semantic ‘meaning’. Where does it say that in computational semantics the compiler is the holder of the primary view point? My understanding is that computational semantics is about facilitating programmer cognition that can be expressed in ways that can be executed by a computer.

    If we were only interested in the view point of the computer, we’d just write byte-code. OO constructs are, in my mind, a set of practices for the benefit of human beings, and the compilers which can turn them into executable code are just tools.

    After all – someone had to have the idea of interfaces and abstract classes before there existed a compiler that could interpret that command.

    The fact that the byte code pushed out by the compiler in each of your (corner) cases is identical is coincidence, and won’t be the case in all OO compilers, where as the specific meanings of interface vs abstract remain constant (and different) to a group of human beings exposed to OO theory.

    Semantically they are *not* the same thing, unless you are a (specific) computer chip.

    But, even if I bought your argument that a totally empty abstract class and an interface are identical in ‘meaning’ because of the byte-code generated by the compiler, aren’t totally empty abstract classes a bit pointless? Isn’t the power of an abstract class in the way it differs from an interface – it can provide basic behaviour shared by all the subtypes. Even if all you’re implementing is the a logic template pattern, with all the steps filled in by super types.

    So – taking even the most basic ‘useful’ implementation of an abstract class, one that has a template method that calls two abstract methods to be overwritten in the extending class, the byte code for that abstract class would differ from the byte code of the interface that describes the contract that class can implement.

    In addition, if I place body in an interface method the compiler will puke. If I put code in an abstract class method, the compiler doesn’t mind.

    This tells me that even your compiler thinks that these two things have a different ‘meaning’… they are semantically different when being digested even if they produce the same byte-code after digestion.

    If they only become the same *after* compilation, then perhaps it is the interpreter alone that considers them to be the same?

    So – whether you favour the human view point (and I do) or the computer’s (as you do) – it seems to me that ‘interface’ and ‘abstract class’ only mean the same on occasion – the majority of the time they mean something really quite different.

  8. @Glen,

    I’m pleased your mind wanted to focus on abstract classes and not on the benefits of interfaces, for I wasn’t questioning the clear benefits of interfaces πŸ™‚

    @Stray,

    Consider the code:

    If the compiler generates identical bytecode for i++ and ++i, then the two statements are semantically identical. If the compiler generates different bytecode, then the two are semantically different. Whether you or I see them as meaning the same is of no consequence. The language rules, as implemented by the compiler, define a language’s semantics. I guess we aren’t going to agree on this point though. So I’ll drop the use of “semantically identical” and will use “functionally identical” to describe my abstract class and interface instead.

    To both of you, I find it odd that you both ask “what would be the point of your abstract class”. I would have thought the reason obvious. It defines a contract that an implementing class must fulfil. In a language like my imaginary one, Lapsan, a class can “sign up” to many of these contracts. In other words, a fully abstract class is an interface! πŸ˜€

    Glen raises an apparently good point that an important difference between a fully abstract class and an interface is that the fully abstract class can be turned into a partially abstract class at a later date by adding concrete content to it. I say apparently as the same applies to an interface, save that in most languages I can think of, you have to change the word interface to class (or the equivalent) too.

    The “you have to change the word interface to class” seems to me to be the real reason folk refuse to accept a fully abstract class and an interface are identical. How can they be identical when they have different names?

    Anyway, thanks to Stray, Eric and Glen for taking the time to comment. With my better understanding of people’s objection to my abstract class (with multiple inheritance) == interface claim, I can get back to writing my “Should we scrap interfaces?” post…

  9. First of all, an abstract class that contains default implementations _is_ “fully abstract”. There is no such thing as a “partially abstract” class. An abstract class is a class that has no direct instances. A concrete class is a class that can be instantiated. It cannot be “sort of” instantiated.

    And, no, an intentionally empty abstract class is not a contract that must be fulfilled. First of all, there is no contract. An empty, abstract class would have no methods. And, even if you added some empty methods, it’s still not a contract because classes that extend the abstract class have no obligation to implement those methods. If both sides do not agree to something, you do not have a contract, you just have hope.

    Finally, if you have to change an interface to become a class, you are no longer comparing interfaces to abstract classes, you are now comparing classes to abstract classes. I think you really miss the point when you think that interfaces and classes are the same thing because all you did was change some text. By that logic, a “flower” and a “speeding locomotive” are the same thing because it’s just different text.

    You’re completely misreading people if you think their objection to your argument is because you have to “change the word”. They’re objecting because changing the word made a _real_ change. You no longer have the same thing. It may just be different letters to your keyboard, but it is a real difference to the compiler, application behavior, etc.

    It appears that you are now trying to claim that an “abstract class” and an “interface” are exactly the same because a “concrete class” has some similarity to an abstract class. You’re using a 3rd object to try to prove the similarity of 2 other objects. Your argument is like saying an elephant and a tree are exactly the same thing because a tree could be turned into a table … and elephants and tables both have four legs.

  10. I suppose you could use abstract methods to force the abstract class to behave like an interface. But, just because you could use an abstract class as if it was an interface, does not make them the same thing.

    I could use the back of a drill to hammer in a nail. But, that does not mean that the drill _is_ a hammer or should be used instead of a hammer (for nailing).

  11. @Glen,

    I’m trying to understand your paragraph that starts “And, no, an intentionally empty abstract class is not a contract that must be fulfilled…”. Consider the following code:

    Where in this code does the contract begin and end and where does the implementation begin in your view?

  12. Glen’s point, and mine, is that there is a world of difference between a standard and ANY concrete item that fulfils the standard. Or contract.

    The purpose of them is different. The intent is different. The idea communicated is different. The way most compilers generate the code in most cases is different…

    I have great difficulty seeing how they are ‘the same’ in any context. As Glen says, I sometimes use my fork to cut my food, but that doesn’t mean it’s a knife.

    But also – why on earth would you want to do away with interfaces? Interfaces are *great*. If a ‘fully’ abstract class is like an interface, why bother? What’s the big deal. We already have that problem solved…

    If you are bothered by the fact that you have to type some extra code to implement an interface, vs not to extend an abstract class, you seriously need a better IDE ;P

  13. @Stray,

    The invitation to tell me where the contract and the concrete begin and end in my example is open to you too.

    As to why I’d want to get rid of interfaces, it’s because they are not truly fit for purpose. They should be replaced with implied abstractions, composition through inheritance and duck contracts. All of these terms are subject to name change as I write the post πŸ™‚

  14. First off, I kind of blew it in that paragraph by not discussing the use of abstract methods to accomplish your desired contract behavior. I couldn’t edit the comment, and had to settle for adding another comment, after the fact.

    I think what I was trying to say was that an abstract class with no methods is not a contract that must be fulfilled, because it is not claiming it does anything at all – there is nothing that you must do (which goes back to the part about “what would be the point of your abstract class”). I probably should have just stopped there, as I think that finished the point.

    With the hesitation that it feels like I’m stepping into a trap, I think we’d all agree that the method declarations ending in a semi-colon are contracts … and the methods employing curly braces denote implementation.

    I guess I’m a little confused by a couple of your statements. Earlier, you said that you were not “questioning the clear benefits of interfaces”. Later, you said that you wanted to “get back to writing my “Should we scrap interfaces?” post.”

    As Stray asked, “why on earth would you want to do away with interfaces?” You say they have clear benefits, but want to suggest getting rid of them. I feel like I’m chasing my tail. I’m not sure I understand what you are trying to get at.

    If I had to guess, I would say that you are hoping to claim that you can use abstract classes in both ways (scaled down to be like an interface … or with implementations to be like, well, abstract classes).

    But, if that’s the case, why stop there? Why not get rid of _both_ abstract classes and interfaces? Just let classes declare methods ending in semi-colons as requiring implementation somewhere down the line. Then you can have little classes that act like interfaces and classes that can’t be directly instantiated that behave like abstract classes. Further, why have classes and objects at all? We could just have one huge file with GOTO and stuff like that.

    I think there are benefits to being clear about what you’re trying to code. I actually think requiring the developer to actually make the specific decision is a good thing, not a hassle that we should try to hide by making one super-mondo-class-thing that can do anything we dream of.

  15. It’s interesting that you mention duck typing, because that definitely feels like a step backwards. One of the great benefits of strongly-typed languages is compile-time checking. For many things, you immediately find out about mistakes in your code. Duck typing is a technique that would hide your mistakes from you (you may have passed the wrong object, you may be making a call on the wrong object, or you may have just had a typo in the method name). You don’t find out about using a class that doesn’t have the expected methods until runtime (and, only when the situation occurs – you could be discovering bugs for a long time … rather than having been alerted to it as soon as you made the mistake).

    And, how in the world would you keep track of what the method names _should_ be. I might code start() in one class, you might code go() in a different class, someone else might code execute(), someone else might startnow(), someone else might code startNow(), etc., etc., etc. There would a whole lot of variations, typos, etc. I would bet that you would actually end-up with _no_ functional interfaces (unless you were extremely disciplined … which would be way more work and way less fun than just using interfaces).

    You say interfaces are not fit for the purpose. In what way? They seem pretty good to me (and, from what you said, to you too!).

    I’m trying to imagine giving someone an API that has “implied interfaces.” I envision someone smoking something and saying, “Yeah, man, just call whatever you want. If you’re calling the right thing on the right object, it’ll work.” But, how do I know if I’m calling the right thing on the right object? Do you have interfaces or something? “Naw, man, if you do it wrong you’ll know because it’ll blow-up in production. You dig?”

  16. If you don’t, by this stage, see that there is a difference between concrete and contract – that no plain white tee is the ‘same’ as the universal agreement on *what* a tee-shirt ‘is’ – then I give up on that line.

    So – ignoring semantics, and looking pragmatically – the empty abstract does not force the extending class to extend all those functions, and so it is not a contract at all.

    I agree with Glen that duck-typing is a huge step backward. Can I get a side of RTE with that crispy duck? Thanks.

    If you feel that interfaces aren’t ‘fit for purpose’ – it would be a good idea first to state what you think the ‘purpose’ of an interface is. I believe that they are fit for purpose (as the common ground defines that purpose, which is what my first comment was about), it’s just that for some reason you don’t agree that the purpose is worth achieving. This is a different argument from saying they are not fit for purpose. Yes?

    I can’t figure out that reason at all, and to be honest I don’t feel like a single comment Glen or I have made is ‘going in’ – it’s like you’ve got a deflection shield on. So – either you’re smoking something that we don’t have around here, or you’ve reached a new level of OO understanding that is beyond us mortals! Either way, good luck with Lapsan, I’ll be over here, coding-by-contract through interfaces – I’ve given up RTEs for New Years.

  17. is it worth pointing out that you don’t actually get the same bytecode when compiling java interfaces and abstract classes?

    You do mention this as one of your points.

  18. how odd, never noticed there is a very very tiny smiley face on the bottom left of this blog πŸ™‚ cute

Comments are closed.