[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

MOP comments part 1.



    Date: Fri, 4 Dec 87 17:27:14 CST
    From: Patrick H Dussud <DUSSUD%jenner.csc.ti.com@RELAY.CS.NET>

    I like this draft much better than the first draft that came out
    last march.

Glad to hear it.

    - Section: Class Organization in the CLOS Kernel

    I find the argumentation in favor of common base design not very
    convincing. 

I agree that the argumentation presented in the current draft is not
very convinving. See below.

	    Having the mixins is fine if you have cut
	    the world exactly right for the variation of class behavior one wants. 
	    However, if not, then one has the same type of problem with overriding
	    unwanted behavior with multiple mixins

    I agree with this. If we think that we can't get it right in a reasonnable
    amount of time, then I want to suggest an alternative:

    (defclass basic-class ())
    (defclass standard-allocation-class (basic-class))
    (defclass structure-allocation-class (basic-class))
    (defclass standard-class (standard-allocation-class) ...)
    (defclass structure-class (structure-allocation-class) ...)
    (defclass built-in-class (basic-class))

    That's a minimal approach that preserves modularity (no turning off/on methods.)
    and conveys the fact that there is only two standard ways to represent
    instances. 

Well, I believe that we may want to go to a structure like:

(defclass basic-class () ...)
(defclass standard-class (basic-class) ...)
(defclass structure-class (basic-class) ...)
(defclass built-in-class (basic-class) ...)
  .
  .

but I think doing even that will be hard in a "reasonable ampount of
time".  The point is this.  In this organization, what behavior do you
put in basic-class and what behavior do you put in standard-class?  Can
you make a lasting, satisfying argument for that breakdown?

So far, we have been unable to come up with a division of behavior that
we can make a lasting satisfying argument for.  It may be that we will
want to go to a structure like the one above, and just take a decent
crack that the division without worrying about whether the division
appears lasting.

The real question seems to be:

  If you go to a separated class structure, must the division be
  appropriate just for the defined classes, or must it somehow
  be more 'correct' in general.  That is, when making a decision
  about what should go in basic-class, should that decision be
  defended only with respect to the standard-class, structure-class
  and built-in-class or should it somehow be reconciled with some
  more abstract notion of class division.

If we only reconcile the division with respect to the existing classes,
we are a likely to get what looks like a good modularity, but as soon as
someone tries to extend it they will discover it isn't so good.  On the
other hand, if we try to reconcile the division with all future programs
in mind we will never be able to do the division.  Clearly we must find
a stable middle ground in this dimension.  Having spent some time
pursuing several different such middle grounds, I am starting to believe
that a structure like the one I mention above is appropriate, but even
in doing that, we will have to make some design decisions which in the
future will appear more awkward than if we just have everything be a
subclass of standard-class.

    - Section: The Named Class Definition Protocol
 
    Why would we have to parse the slots at load time instead of compile time?
    Add-named-class should be able to accept slot-descriptions as well.

I suppose thats true.  I wouldn't expect the efficiency gain to be
tremendously significant since the slot specifiers can be canonicalized
at compile time, and there is so much other work to do.

    This Class Update protocol based an eager evaluation model.  I want to propose a
    lazy evaluation model.  There is no need to propagate changes downward (to the
    subclasses) if the subclasses haven't computed anything from their superclasses.
    Computed properties are typically: PCL, effective slot-description, effective
    default-initargs...  There is no reason for computing these properties if the
    class is not going have instances since a class cannot compute its
    effective propeties based on the effective property of its
    superclasses.

Lazy evaluation is harder though, and this would force user mop code to
have to be able to deal with lazy evaluation.  I think an appropriate
middle ground can be reached by having the full walk happen, but having
it not do all the computations (like cpl and slots) until finalize
inheritance time.

    I also propose to get rid of forward-reference-class. The direct-supers
    slot of a class is never mapped to class object. When finalize-inheritance is
    called, the mapping is done in order to compute the CPL and other effective
    properties but the direct-supers slot is not updated. I thinks it reflects better
    what the user expects if the mapping between name and class object
    changes. 

Actually, I think the semantics of using forward referenced class
objects are much simpler and easier to define.  I don't believe this
affects the naive user (defclass only) model at all (or not very much)
and it makes the sophisticated users model easier to deal with. Having
an object to represent the forward referenced class makes it possible to
store forward-declared information about that class; this makes it
possible to implement interesting behavior like the declare-optimized
example.
-------