I accidently sent this directly to Richard. Sorry about that, folks...
-- Forwarded message --
From: Jonathan Lang [EMAIL PROTECTED]
Date: Aug 29, 2006 1:24 PM
Subject: Re: Classes / roles as sets / subsets
To: Richard Hainsworth [EMAIL PROTECTED]
Richard Hainsworth wrote:
I find classes and roles, and multiple inheritance in general, difficult
to understand. Larry Wall talked about subsets, so I have tried to
analyse various situations using the idea of sets and subsets and Venn
diagrams for demonstrating the relations between sets and subsets. The
idea is that the 'space' encompassed by a set in the diagram (labelled
as sets) is method functionality and attributes.
This may well miss the mark. Some of the most important differences
between classes and roles come in when the sets of method namespaces
don't match up with the sets of method implementations - that is, A
and B both include a method m, but A's method m does something
different than B's method m.
See diagram Case 1 (Class B is a subset of class A):
Note that in Case 1, there isn't much difference between classes and roles.
My understanding of inheritance in other languages is that Class A 'isa'
Class B, and inherits all of the attributes and
functionality of Class B, and extends functionality and attributes.
So far, so good. If you want A.m to do something different than B.m,
A redefines m.
It is also possible for Class B to be ('isa') Class A, and ignore the
extra functionality of A, presumably to create objects that are smaller
than the more general class.
Not according to clean OO programming theory. If A isa B, then A will
carry with it all of B's internal mechanisms, even the ones that it
has closed off from public access. If it fails to do this, it isn't
really a B. Even when A redefines how m works, it includes an
implicit mechanism for getting at the original definition. As such,
inheritance can only add to a class; it cannot remove or change
anything in any substantive manner. The only point at which stuff
gets removed is when the code optimizer comes along and trims the fat.
Let's extend Case 1 by adding a Class C, which is a superset of Class
A. C isa A, but A isa B; C can still access B.m, as well as A.m.
Think of A, B, and C as being layers that get added on top of each
other: A covers B, but doesn't actually replace it.
My suggested interpretation of roles:
Class B is a role, and Class A is built from Class B, extending its
functionality. A role without extra code becomes a class if it is
The motto for role A is anything you can do, I can do too. Note
that when role A declares that it does role B, it makes a promise
about _what_ it can do, but makes no promises about _how_ it will do
it. In fact, roles don't even make a promise to supply any
implementation information at all: B doesn't have to say a word about
how m works - and for the purpose of composing roles, what it _does_
say about how m works should be taken not so much as a rule than as a
guideline. As long as the composer has no reason _not_ to accept B's
version of m, it will; but at the first hint of trouble, B's version
of m will get jettisoned.
In Case 1, the only way that role B's version of m will get jettisoned
is if role A provides its own version. However, A is not a B; it is
its own unique entity. If A invalidates B's suggestion for how m
should work, then nothing that does A will implicitly have access to
B's version of m. Unlike classes, roles can change from what they're
composed from, not just add to them. However, because they don't
guarantee to tell you how anything works, they can't be used to
intantiate objects; that's what Classes are for.
See diagram case 2 (Class A and Class B intersect):
Usual OO technique:
Class B inherits the functionality of Class A, extends the functionality
(in one 'direction') but then over-rides
(anuls) some of the functionality of A (say, by redefining
methods/attributes used in A).
Question: Is this the sort of behaviour that is forbidden in some languages.
Very definitely, yes. Removing capabilities during inheritance is a
no-no. If you wanted Classes A abd B to be part of the same
inheritance tree, you'd have to define a common ancestor class that
contains the intersection of A and B, and then each of A and B inherit
As described, though, A and B are completely unrelated by inheritance;
each is a unique class which stands on its own. The fact that both
contain a method m is a coincidence, nothing more.
This _is_ a useful case to consider, though, in terms of what happens
if you add a new class (C) which encompasses both A and B. Assuming
that m is an element of both A and B, A.m doesn't neccessarily work
the same way as B.m; C.m needs to decide which version to use.
Traditionally, OO languages imnplement a system of seniority, where
one of the classes that C inherits from is given precedence over the
other - generally based on