Buttons and Tigers and Bears (oh my!)

shap@eros.cis.upenn.edu shap@eros.cis.upenn.edu
Sat, 24 Oct 1998 20:34:55 -0400


> I will choose a question that you have likely already answered so
> that we can see how it is resolved in a real application.  Let's
> suppose that you are building a widget toolkit and you want it to
> provide several types of buttons....


First, let's ask a question:  in an inheritance-based design, what
actually happens when the derived class gets cast to a parent class?

Basically, what happens is interface thinning.  The potentially richer
interface presented by the derived class is reduced to that of the
parent class, modulo virtual functions.

Given this, step back for a moment and imagine an object as consisting
of a

     (foo state ptr, foo method tbl ptr)

pair, where all of the methods of foo take a foo* (or better: a foo&)
as their first argument.

>From this, it is not a large step to imagine that there might be many
method tables (interfaces) associated with a foo state ptr, and that
the notion of object can be generalized to

     (X state ptr, table of methods whose first arg is an X&)

Note that the runtime system does NOT need to know what the actual
type X is -- this is polymorphable over the type of X.

Now lets go back to your button example.  Button behavior is actually
an interface specification.  We might imagine this interface to
include a draw method, a mouse-down method, a mouse up method, and so
forth.

Imagine now that we redefine all of these methods so as to use
currying.  That is, a button is an object X and a method table Y such
that

     Y o X yields a structure containing the required methods.

Call this the ``button interface.''

If we take this understanding, then ANY object can become a button
simply by declaring a binding from the button interface structure to
the object's methods.

One can imagine a variety of reasonable ways of simplifying the
programmer effort associated with the binding specification.


So, I guess my answer to the inheritance argument is that it's a
piss-poor way to express an awkwardly restrictive set of interfaces.


Back to your ``method extension'' question.  First, in a secure object
model I'm not clear that such extensions are sound from a security
perspective.  Empirically, the C++ state inheritance properties create
many conditions under which the derived class can violate the internal
design assumptions that are embedded in the implementation of the
superclass methods.

I think I'ld suggest that extension should be accomplished -- if it is
permitted -- by adding a new interface rather than by mutating an
existing one.

> But the more serious issue is the upgrade problem: what happens
> if now i want all my buttons to draw their labels in a different
> font?  Now, i didn't foresee this improvement when i wrote Button.

ARRGGGHHH!

The button has a Draw() method.  It's nobody else's goddamn business
what font the button uses internal to its draw method!!!

Sorry.


By all means, introduce a new object that exports the button interface
containing a draw method and also a *separate* font manipulation
interface (a better design in any case, as font manipulation
interfaces have common stuff that is orthogonal to drawing semantics).



Summary:  inheritance is a bad second cousin to interfaces that
encourages you to commingle things that are orthogonal...


Jonathan