Classes as Packages (was: Harvesting infrastructure)

Anthony Hannan ajh18 at cornell.edu
Tue Nov 19 04:55:25 UTC 2002


Nathanael Scharli <n.schaerli at gmx.net> wrote:
> I agree with you. Your critics on MI is just about what inspired us to
> do the Traits work. Have a look at the latest draft of the Traits paper
> (http://www.iam.unibe.ch/~schaerli/traits_draft/traitsDraft.pdf) and you
> will find a detailed description of good reasons why MI ddidn't make it
> into recent languages. I hope that Traits are going to be more
> successful ;)

I read the new draft version of Traits, and I commend you, Stephane,
Oscar, and Andrew for your thorough work.  But I have to say, I don't
see a clear advantage of it over multiple inheritance without state. 
"Without state" means replacing instance variables with primitive
accessor methods that only work on concrete instances of their method
class.  Every class has to define its own accessors, but they can be
generated automatically from superclasses.

	Let me go over the so-called disadvantages of MI raised by the Traits
paper and try to refute them.
	"Limited compositional power" - This was the most compelling argument
in favor of traits.  But the traits solution to the SyncReadWrite
example uses 'super read' in its trait without implementing it, making
it a requirement of the trait (implicitly or explicitly, it does not
matter).  Since it is a requirement you could just as well name it
anything like asyncRead and not use super.  In fact, use of super in
traits does not mean anything when looking at the trait by itself, so I
question its appropriateness.  In multiple inheritance, I would have
SyncReadWrite call asyncRead and define it as 'self
subclassResponsibility'.  Then I would have SyncA inherit from A and
SyncReadWrite, and define SyncA>>asyncRead as 'super.A read' and
SyncA>>read as 'super.SyncReadWrite read'.
	"Acessing overriden features" - To limit this problem in multiple
inheritance, I would restrict classes to naming their immediate
superclasses only as in 'super.A', where A is an immediate superclass. 
I agree this does tie the hierarchy into the code a bit, but I think it
can be managed pretty easily.  If the A superclass get removed from the
class all methods that have super references to it could be brought to
the users attention, or they will raise an error if executed.  It is not
much different from removing an instance variable from a class and not
updating methods that reference it.
	"Conflicting features" - Since I am proposing no inheritance of state,
this is not a problem.  Even the Traits paper says "Whereas method
conflicts can be resolved relatively easily (e.g. by overriding),
conflicting state is more problematic", page 4.
	"Two contradictory roles: instance generators and unit of code reuse" -
The Traits paper claims that this pushes classes to be complete classes
instead of just small units of reusable code.  I say what about the
concept of abstract classes, they are not meant to be complete or
instantiated, just shared by subclasses.  They don't even have to be
subclasses of Object.  I think abstract classes without state are analogous
to traits.

	I think that is my whole point: abstract behaviors and traits are
analogous.  So why add a new way of defining behavior and putting
them together, yielding two types of behaviors and composition in the
same system.  Even in the future work section of the Traits paper, they
talk about replacing single inheritance and adding state to traits.  This
would wrap them back around to multiple inheritance but in a nested
composition form instead of an inheritance form, which would basically
be the same thing.
	Finally, I think MI is more conducive to reuse than Traits.  If you
want to reuse a class that is outside of your single inheritance
hierarchy, in MI you can just inherit from it, but in Traits you have to
convert the class to a trait which is difficult if you also want to
include its inherited behavior.

Cheers,
Anthony



More information about the Squeak-dev mailing list