Newsgroups: comp.lang.dylan
Path: cantaloupe.srv.cs.cmu.edu!das-news2.harvard.edu!news2.near.net!news.mathworks.com!gatech!news.sprintlink.net!noc.netcom.net!netcom.com!netcom8!haahr
From: haahr@netcom.com (Paul Haahr)
Subject: Re: What is Primary Class for?
In-Reply-To: derway@ndc.com's message of 01 Jun 1995 00:28:40 GMT
Message-ID: <HAAHR.95Jun1211751@netcom8.netcom.com>
Sender: haahr@netcom8.netcom.com
Organization: NETCOM On-line services
References: <DERWAY.95May31172842@alumni.ndc.com>
Date: Thu, 1 Jun 1995 20:17:50 GMT
Lines: 82

Don Erway derway@ndc.com wrote:
> The DIRM mentions that a class may only have one "primary" superclass.  It
> says that the opposite of "primary" is "free", and that this is the default.
> It then mentions these two again in the section on controlling dynamism.
>
> It never says what primary is for.

This is a problem with the DIRM being interim.  We all assume the real
reference manual will go into more detail.

> I assume it is not trying to say that every class has to have
> exactly one primary direct superclass, (thus implying something like
> only single-inhertance + mixins is allowed).
> 
> It seems to be saying that if it has any, it can only have one.

Close but not quite.  Classes can have no, one, or many primary
superclasses, but each primary superclass must have all of the other
primary superclasses as either a subclass or a superclass.  So, for
example, this is valid:

  define primary class <a> (<object>) ... end;
  define free class <b> (<a>) ... end;
  define primary class <c> (<a>) ... end;
  define free class <d> (<b>, <c>) ... end;

> So is "primary" strictly an opportunity for optimization, or does it
> have some semantic significance?

It, like sealing, is there to facilitate optimization.  Two forms of
optimization are possible based on this information.

First, the slots in a primary class can be stored at known offsets,
which is not true in the general case of multiple inheritance.  For
example, in this program fragment

  define open primary class <person> (<object>)
    slot age;
  end class;

  define sealed generic age (<person>);

  define method retirement-year (person :: <person>)
    ... person.age ...
  end method retirement-year;

the compiler can optimize the expression ``person.age'' into a
constant offset fetch from the beginning of the object ``person''.
If the class is not primary, that optimization can't be done.

Second, if a class is primary, you know that it's disjoint from
primary classes other than ones it inherits from or that inherit from
it, which is useful information when doing compile-time dispatching of
generic functions.  For example, given

  define open class <surface> (...) ... end;
  define open primary class <window> (...) ... end;
  define open primary class <bitmap> (...) ... end;

  define sealed generic draw-simple (surface :: <surface>, ...) ... end;
  define method draw-simple (window :: <window>, ...) ... end; // DS1
  define method draw-simple (bitmap :: <bitmap>, ...) ... end; // DS2

  define open generic draw-complex (surface :: <surface>, ...) ... end;
  define method draw-complex (window :: <window>, ...)
    ... draw-simple(window, ...) ...
  end method draw-complex;

Because <window> and <bitmap> are primary classes and draw-simple is
sealed and has only the two methods on it, the call to draw-simple in
draw-complex can safely be turned into a call to the method DS1.  If
<window> and <bitmap> were not primary, a common subclass could be
defined which would make DS2 the most applicable method.

The seal generic form is a clearer way of expressing the relationship
in this example.

Note, by the way, there is usually little reason to declare a sealed
class primary.  (One can easily construct circumstances where it could
matter, but it would probably be rare in practice.)

Paul
