What creates inheritance?

March 4, 2015

It all started with an @eevee tweet:

people who love inheritance: please tell me what problems it has solved for you that you don't think could be solved otherwise

My answer was code reuse, but that started me down the road of wondering what the boundaries are of what people will call 'inheritance', at least as far as code reuse goes.

These days, clearly the center of the 'inheritance' circle is straight up traditional subclassing in languages like Python. But let's take a whole series of other approaches to code and object reuse and ask if they provide inheritance.

First up, proxying. In Python it's relatively easy to build explicit proxy objects, where there is no subclass relationship but everything except some selected operations is handed off to another object's methods and you thus get to use them. I suspect that the existence of two objects makes this not inheritance in most people's eyes.

What about Go's structure embedding and interfaces? In Go you can get code reuse by embedding an anonymous instance of something inside your own struct. Any methods on defined for the anonymous instance can now be (syntactically) called on your own struct, and you can define your own methods that override some of them. With use of interfaces you can relatively transparently mix instances of your struct with instances of the original. This gets you something that's at least very like inheritance without a subclass or a proxy object in sight.

(This is almost like what I did here, but I didn't make the *bufio.Writer anonymous because there was no point.)

How about traits, especially traits that allow you to override methods in the base object? You certainly don't have a subclass relationship here, but you do have code reuse with modifications and some languages may be dynamic enough to allow the base object's methods to use methods from a trait.

So, as I wound up theorizing, maybe what creates inheritance is simply having a method resolution order, or more exactly having a need for it; this happens in a language where you can have multiple sources of methods for a single object. On the other hand this feels somewhat like a contorted definition and I don't know where people draw the line in practice. I don't even know exactly where I draw the line.


Comments on this page:

By Chris N at 2015-03-04 10:12:17:

I would argue that it's not method resolution order (MRO), either. Perl's Moose object system provides a couple different ways for classes to have multiple sources of methods (without including subclassing), and thus requires an MRO. These multiple sources include the class itself and then any roles and traits composed into the class (and any roles / traits those roles / traits have composed into themselves, etc.).

I would then argue, based on this, that "inheritance" is simply an umbrella term for a (inconsistently defined) set of concepts, some of which are artificial or based in nomenclature rather than form or function. As an example, let's say we have a Point class. And then we have a subclass, Point.ThreeDimensional. Point.ThreeDimensional inherits from Point, but at the same time we can express this using proxy objects, Go's embedding and interfacing, and roles / traits.

tl;dr we don't know what we're talking about

I think (but am not yet sure) the defining point is what happens if you go back and add a method to the superclass that was not there when the subclass was being written.

Written on 04 March 2015.
« The latest xterm versions mangle $SHELL in annoying ways
An interesting excursion with Python strings and is »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Mar 4 01:08:17 2015
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.