The Multiple Inheritance Conundrum, interfaces and mixins
Archive - Originally posted on "The Horse's Mouth" - 2010-04-11 22:08:20 - Graham Ellis
Should an OO programming language support "multiple inheritance"? Let's define multiple inheritance first - starting from simple (single?) inheritance.
(Single) Inheritance.
I don't want to have to define each type of thing ("class of object") from scratch, so I'll define once class as being based on another. Then I don't need to (re)define all the code, or copy all the code from the base class - I can just say "here are the named blocks of code that are different".
So - for example - I can define a base type of "animal" and then define a "pet" that's based on an animal - i.e. pet inherits from animal, and the pet class only need contain those things that differ. Having set up a pet, I can set up a farm animal, a wild animal and a mythical animal in a similar way - just defining the changes which is much more efficient - especially when it comes to maintainance - than copying / repeating huge lots or code.
Multiple Inheritance
So a pet is based on an animal. Good - but let's say that I want to additionally base a pet on something else - such as a possession. Pets, Houses, cars all want to be based on possessions and share code, and that's what we mean by multiple inheritance.
But multiple inheritance is complicated to implement in a language, and it can make it very hard for the user to design his structures too. The complications start as soon as you try to create an object - in many languages, as soon as you say "I want a pet", the constructor for an animal will automatically be run as a pet is an animal - leading to a problem as to how it can start by building an animal, and start by building a possession.
Some languages such as C++, Python ([example]) and Perl allow multiple inheritance - the language has the complexity, and the programmer who has a clear head may use it. But other languages do NOT support multiple inheritance. There are two alternatives - "Multiple inheritance very lite" and "Multiple Inheritance lite" if you like.
Multiple Inheritance very lite - Interfaces
One of the major reasons you might want multiple inheritance is to support polymorphism in languages where the data structures are strongly typed, or there are variable privacy rules. (In English - you might want to group types of thing by behaviours - such as an array of possessions, so that you can always call a piece of code "getinsurancevalue" even if the objects differ in detail and how they handle such a call).
Interfaces allow for this behaviour - you can define an interface in languages such as Java and PHP, and say that a class "implements an interface" ... and then you can have variables that contain a lot of very different - but all possession - objects.
Interfaces are indeed very light. Code is not shared, so if there is to be common code it needs to be repeated. But sometimes they are a very good and sufficient soloution.
Multiple Inheritance lite - Mixins
A Mixin provides you with the ability to pull in common code as well as a common interface into a class which also inherits from elsewhere - it's really like an interface, but rather more so as it does contain code as well. So in the case of our possession, common code to set and get the insurance value of a possession might be stored in a Mixin.
Both Python and Ruby support mixins, and at the end of last week I wrote a fresh example in Ruby to show them in use.
Here is the Ruby code used to ...
module Insurable
def setiv(newval)
@iv = newval
end
def getiv()
return @iv * 1.035
end
end
Here is how my House brings in that code ...
require "mixmodule"
class House
include Insurable
def initialize(numrooms, addy, numfloors, value)
@numrooms = numrooms
@addy = addy
@numfloors = numfloors
setiv(value)
end
def getfloors
return @numfloors
end
end
And here is how my pet brings it in ...
require "mixmodule"
class Pet
include Insurable
def initialize(name,breed,value)
@name = name
@breed = breed
setiv(value)
end
def getname
return @name
end
end
things.each() do |item|
mread = item.getiv
print "#{item} #{mread}\n"
end
By its very nature, Multiple Inheritance and the lighter alternatives are useful in medium sided to larger applications rather than the small training examples that I write here. So this example of Mixins hasn't actually used the standard single inheritance that I have available to me .. to let pet inherit from anial, and house from residence.