Modeling multiple inheritance

oleg at pobox.com oleg at pobox.com
Fri Sep 26 21:19:29 EDT 2003


Brandon Michael Moore wrote regarding the first solution: chain of
super-classes:

> I'm worried about large class hierarchies. If it works on the
> java.* classes I should be fine. Have you used this approach before? I'm
> worried about compile time, runtime costs from the casts (hopefully they
> compile out), and maybe exceeding maximum stack depth in context
> reduction.

I didn't use the approach for anything as complex as all java.*
classes. The only run-time costs are evaluating the chain of fst . snd
. fst . .... The length and the composition of the chain is statically
known. Perhaps the compiler can do something smart here. The maximum
length of the chain is the maximum depth of the inheritance tree. It
shouldn't be too big. A cast from a subclass to a superclass has to be
executed anyway (if not by your code then by JVM). If the maximum
stack depth is exceeded, we can repeat the compilation with a compiler
flag to allocate a bigger stack. In my experience the only time I've
seen the derivation stack depth exceeded is when the derivation truly
diverges.

> What type heap? It sounds like you are talking about information from an
> OO runtime, or are you talking about the collection of instances.

The other solution I talked so confusingly before is that of generic
functions. For that, we need a way to obtain a value representation of a
type. Several such representations exists: e.g., Typable,
representation as an integer, etc. All our objects must be members of
the class Typable. A method (generic function foo) would have the
following signature:
	foo:: (Typable object) => object -> Int ->Int

For example, if foo is defined for ClassA object only, we can write

	foo obj arg = 
	    if inherit_from (typeof obj) (typeof (undefined::ClassA))
	    then particular_instance_foo (coerce obj) arg
	    else error "miscast"

If bar is defined for classB and redefined in classC, we can write

	bar obj arg = 
	    if inherit_from (typeof obj) (typeof (undefined::ClassC))
	    then particular_instance1_bar (coerce obj) arg
	    else if inherit_from (typeof obj) (typeof (undefined::ClassB))
	    then particular_instance2_bar (coerce obj) arg
	    else error "miscast"
			
The functions inherit_from and coerce avail themselves of a table that
records the relationship between types using their value
representations.

The disadvantage of this approach is that the cast errors become
run-time errors. OTH, because type representations and the whole
inheritance graph are values, we can do much more. We can check for
proper and improper diamond inheritance, we can do a rather
sophisticated dispatch.

Types heap and several ways of doing safe casts are discussed in

http://www.haskell.org/pipermail/haskell/2003-August/012372.html
http://www.haskell.org/pipermail/haskell/2003-August/012355.html

See also:
	http://citeseer.nj.nec.com/cheney02lightweight.html
	http://citeseer.nj.nec.com/context/1670116/0
	The Sketch of a Polymorphic Symphony
	http://homepages.cwi.nl/~ralf/polymorphic-symphony/


More information about the Haskell-Cafe mailing list