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

intro material



Commenting on this went pretty quickly.  Indented material is an excerpt
from the TeX source, provided to give context.  References to Symbolics
CLOS in many cases refer to the undocumented and unsupported metaobject
protocol in our implementation, so these aren't necessarily things that
we would be extremely resistant to changing.

Moon noticed some typos and garbled English, which it would be too much
trouble to report.  If you don't have a local copy editor, let me know
and I'll mail you a marked up hardcopy.

This implies that class names must be symbols, which contradicts 88-002R
and current practice.

This implies that class, generic function, method, method combination,
and slot definition documentation must be a string, but documentation
can be NIL or a string.

What you call METAOBJECT, Symbolics CLOS calls META-OBJECT.  We don't
know which spelling is more correct English usage, but switching to
METAOBJECT isn't a problem for us.

This document consistently uses the term "function specifier" but X3J13
uses the term "function name" for the same thing.  88-002R uses
"function name" under DEFCLASS but "function specifier" under DEFGENERIC
and DEFMETHOD.  When 88-002R's writeup for DEFMETHOD was put into
chapter 6 of the ANSI CL draft, "function specifier" was changed to
"function name", so the latter seems to be the preferred term.

The inheritance structure table shows that STANDARD-GENERIC-FUNCTION is
a subtype of STANDARD-OBJECT.  This is true in Symbolics CLOS also, but
Moon wonders if it's really right, since STANDARD-OBJECT is supposed to
supply the methods for objects of metaclass STANDARD-CLASS, and generic
functions do not have that metaclass.  It seems like you would at least
need a class analogous to STANDARD-OBJECT, which can override any
unwanted methods inherited from STANDARD-OBJECT; in Symbolics CLOS there
are classes named CLOS-INTERNALS::DISPATCHING-FUNCALLABLE-INSTANCE and
CLOS-INTERNALS:FUNCALLABLE-INSTANCE which sort-of fill this role; there
doesn't seem to be anything at all like this in the inheritance
structure table.  Perhaps there should be, I don't know.  There was also
some inconclusive X3J13 discussion of whether a class whose metaclass is
a subclass of STANDARD-CLASS must get STANDARD-OBJECT as a superclass,
or whether STANDARD-OBJECT is only a mandatory superclass when the
metaclass is exactly STANDARD-CLASS.  In any case this issue ought to be
discussed in the document and the rationale for whatever is decided set
forth.

Is interposition of metaclasses allowed?  I.e. when the document says
the class of GENERIC-FUNCTION is FUNCALLABLE-STANDARD-CLASS, does this
mean the class must be exactly FUNCALLABLE-STANDARD-CLASS, or can it be
an implementation-specific subclass of FUNCALLABLE-STANDARD-CLASS?
The document should say yes or no on this issue.

The inheritance structure table shows DIRECT and EFFECTIVE subclasses
of STRUCTURE-SLOT-DEFINITION, but these were not needed in Symbolics CLOS.
I'm not positive of the reason, but it seems to be that structure classes
do not have separate direct slots; because of the way DEFSTRUCT is specified,
inheritance is finalized during the expansion of the DEFSTRUCT macro, and
so a structure class only has effective slots.  Also remember that structure
slots don't have accessors in the same way that standard slots have them.
I don't presently have a concrete suggestion here.

It is a mistake that the base class of all CLOS methods is also the
class used for things defined with DEFMETHOD.  There should be a class
like STANDARD-USER-METHOD which has STANDARD-METHOD as a superclass.
Why?  There are methods which are applicable to things defined with
DEFMETHOD which aren't applicable to accessor methods.  For example,
what is METHOD-FUNCTION of an accessor method?  In our implementation,
it is meaningless (we return NIL).

     \item{\bull} The name, allocation, and type are available as forms that
     could appear in a {\bf defclass} form. 

These aren't forms.  Remember, forms are things that get evaluated.

Just a day or two ago I was wondering why the allocation isn't reflected
in the class of the slot definition instead of as an attribute of the
slot definition.
     
     \item{\bull} A flag which permits optimization of slot access even in
     the presence of applicable user defined methods on the slot access
     generic functions.

Is "permits" the right word?  Perhaps "controls" or "influences"?  Need
to see the documentation of what this is about, to know.
     
     \item{\bull} The methods associated with the generic function are
     available as a list of method metaobjects. 

Also need the list of initial methods (the ones that come
from the defgeneric).  The reason is that if the list of initial methods
in a DEFGENERIC changes, the ones that are no longer in the DEFGENERIC
should go away, unless they have been redefined with DEFMETHOD.
          
     \item{\bull} The function is available as a function.  This function can
     be applied to arguments using the result of an appropriate call to the
     generic function {\bf method-function-applier}.

What is method-function-applier?  We can't evaluate this without seeing
the documentation of that.
     
     \item{\bull} When the method is associated with a generic function, that
     generic function metaobject is available.  A method can be associated
     with at most one generic function at a time.

Mention that if the method is not associated with a generic function,
then the method's generic function is NIL.
     
     \item{\bull} For a given set of arguments, a method $M\sub{2}$ {\bit
     shadows} a method $M\sub{1}$ if and only if $M\sub{1}$ and $M\sub{2}$
     are both associated with the same generic function; and either
     $M\sub{1}$ and $M\sub{2}$ are both primary methods or $M\sub{1}$ and
     $M\sub{2}$ are both {\bf :around} methods or $M\sub{2}$ is an {\bf
     :around} method and $M\sub{1}$ is a primary method; and when $M\sub{2}$
     is invoked, {\bf call-next-method} is called from within its body.
     
     \item{\bull} For a given set of arguments, a method $M\sub{2}$ {\bit
     overrides} a method $M\sub{1}$ if and only if $M\sub{1}$ and $M\sub{2}$
     are both associated with the same generic function; and either
     $M\sub{1}$ and $M\sub{2}$ are both primary methods or $M\sub{1}$ and
     $M\sub{2}$ are both {\bf :around} methods or $M\sub{2}$ is an {\bf
     :around} method and $M\sub{1}$ is a primary method; and when $M\sub{2}$
     is invoked, {\bf call-next-method} is not called from within its body.
     
In "standard" usage, the word "shadow" is synonymous with "override", so
it's dangerous to use the two words to mean two different things.  See
CLtL p.38 and the ANSI CL draft glossary (a document I only refer to when
I agree with it, apparently!).  You should find a different word for
the first of the two bullets; the only word I was able to think of right
now is "wrap".

Also, these descriptions cannot be complete since they say nothing about
the methods' parameter specializers.  I think M2 can only override or
(shadow) M1 when both methods are applicable and M2 is earlier in the
applicable method precedence order.  What I just said has a subtle bug,
because when the specializers are equal and the qualifiers are different,
the relative position in the method precedence order is explicitly 
unspecified.  You'd need to say something like: if they had the same
qualifiers then M2 would be earlier than M1 or at the same position as
M1 in the applicable method precedence order.
     
     \item{\bull} No portable class $C\sub{\hbox{p}}$ inherits from a
     specified class any slot with a name accessible in the {\bf
     common-lisp-user} package.
     
What if it inherits a slot from an interposed class?

What if the slot name is in the keyword package, or otherwise exported
by a specified package but not accessible in the COMMON-LISP-USER
package?  For example, suppose the slot is named IF, the implementation
has two versions of IF, one in COMMON-LISP and another implementation
dependent one, and COMMON-LISP-USER uses the implementation
dependent one.  Then a user program in its own package that doesn't
:use the implementation-dependent package would get shafted by the slot
named IF, but your restriction would not be violated by the implementation.
It would be better to use the standard wording for symbol package restrictions
(see our comments on the previous MOP installment) instead of inventing new
wording that has subtle bugs.
     
     \item{\bull} Methods on portable metaobject classes must be defined
     before any instances of those classes (or any subclasses) are created,
     either directly or indirectly by a call to {\bf make-instance}.  Methods
     can be defined after instances are created by {\bf allocate-instance}
     however.  Portable metaobject classes cannot be redefined.
     
     \beginImplNote
     The purpose of this last bullet is to permit implementations to provide
     performance optimizations by analyzing, at the time the first instance
     of a metaobject class is initialized, what portable Metaobject Protocol
     methods will be applicable to it.  This can make it possible to elide
     calls to those Metaobject Protocol generic functions which will have no
     applicable portable methods.
     \endImplNote
     
Any development-oriented implementation needs to allow for patching of
metaclasses and metaclass methods.  Certainly we've done extensive patching
of that type in Symbolics CLOS.  However, it's true that for programs to
be portable to delivery-oriented implementations they shouldn't depend on
being able to change metaclasses and metaclass methods.  Should they even
be allowed to change non-meta classes and methods in delivery situations?

Is the caveat about ALLOCATE-INSTANCE because the implementation might call
it too soon?  I don't see why the user should be allowed to call it before 
all the methods are defined.