Version 6 of Multiple inheritance with TclOO - how to resolve ambiguities

Updated 2012-01-10 11:34:37 by dkf

Arjen Markus (20 january 2011) A further experiment with TclOO: I remember from a book on Eiffel that multiple inheritance in C++ is actually a potential nightmare: what happens if you have two superclasses with methods or variables with the same name? This leads to ambiguities and they are not elegantly dealt with in C++ (at least that is how I remember it).

The code below constructs a class that has two superclasses, each with a variable myname and a method print. The method seems to be resolved as the print method from the first superclass, but then I get stuck trying to determine which version of the variable myname this composite class gets: I can not reach this variable and the man pages do not seem to give me the information.

A more general question therefore: do we need to explicitly create methods to get the values of an object's variables or is there some syntax that I overlook? (I can live with both, but I'd like to know what is expected). And for this specific case: can we get at the second superclass's print method? (Via next perhaps?) and how do we get at the superclasses's variables at all?

(I hope Donal is not offended by this series of questions - he put a lot of work in TclOO and I am merely going where I have never gone before)

# multiple_inheritance.tcl --
#     How does TclOO behave if two superclasses have the same features?
#

#
# First superclass
#
oo::class create first {
    variable myname

    constructor {} {
        set myname "First"
    }

    method print {} {
        puts $myname
    }
}
#
# Second superclass
#
oo::class create second {
    variable myname

    constructor {} {
        set myname "Second"
    }

    method print {} {
        puts "Hi, my name is $myname"
    }
}

#
# Class with two superclasses
#
oo::class create third {
    superclass first second

    method check {} {
        #
        # This does not work: myname not available!
        #
        puts "Value of myname: $myname"
    }
}

#
# Create an object and check its methods
#
set chk [third new]

$chk print
$chk check
puts "Direct access to myname? [$chk myname]"

DKF: Not offended at all.

> I remember from a book on Eiffel that multiple inheritance in C++ is actually a potential nightmare: what happens if you have two superclasses with methods or variables with the same name? This leads to ambiguities and they are not elegantly dealt with in C++ (at least that is how I remember it).

MI is handled strictly in order by the class hierarchy traversal algorithm. Basically, during dispatch the method implementations come "as late in the depth-first traversal as possible" (that turns out to be the right thing). This linearizes the collection of implementations of a method into a "call chain"; the method is then dispatched along the chain (with traversal to the next step in the chain being done by next; that's exactly what it does.)

> The code [above] constructs a class that has two superclasses, each with a variable myname and a method print. The method seems to be resolved as the print method from the first superclass, but then I get stuck trying to determine which version of the variable myname this composite class gets: I can not reach this variable and the man pages do not seem to give me the information.

There is one myname variable; it exists in the instance’s namespace (as returned by info object namespace). All classes refer to that variable in their methods (though when invoked on different instances, they refer to different variables because the namespaces are different. Of course.) This is how state in TclOO works. I suggest that it is going to be usually better to minimize the amount of state you use, and to document the variables that you create if it is a class where you are encouraging subclasses of it.

> A more general question therefore: do we need to explicitly create methods to get the values of an object's variables or is there some syntax that I overlook? (I can live with both, but I'd like to know what is expected). And for this specific case: can we get at the second superclass's print method? (Via next perhaps?) and how do we get at the superclasses's variables at all?

That's the idea of “properties” and it's not something that's been done yet. It's possible to script in, but that's rather more advanced use of TclOO's features. (And I already covered next.)

APN I wrote an explanation of method dispatching with MI in TclOO at [L1 ]. Hopefully, it is not outdated and not inaccurate.


jcw 2011-02-10 - I'm trying to wrap my head around MI. Following code:

proc start {args} {
  set obj1 [foobar new a b c]
  set obj2 [foo new a b c]
}

class create foo {
  constructor {args} { next {*}$args; puts foo-$args }
}

class create bar {
  constructor {args} { puts bar-$args }
}

class create foobar {
  superclass foo bar
  constructor {args} { next {*}$args; puts foobar-$args}
}

I don't understand how to make MI work w.r.t. constructors. Say a "foo" needs "a" as initial arg, and a "bar" needs "b" as initial arg - how do I pass the proper args to each of their constructors. And what the above also shows: why does foo need to use next to make bar's constructor work? In the second call (obj2), the next will raise an error, because there is no next superclass. But as far as foo is concerned, it has nothing to do with bar, or even whether it coexists as superclass in foobar or not.

Very puzzling... at least when coming from C++.

APN Perhaps the nextto command in newer builds of 8.6 is what you are looking for.
DKF: It's certainly intended to work that way…