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

user interface macros



I have just a couple of substantive, semantic comments on this proposal 
(not just typos nor the sort of minor questions that Jim des Rivieres 
and a couple others had.)  First I want to address the question of
why the focus on defining macros, and then I want to point out a
gap in the current definition of ENSURE-GENERIC-FUNCTION that made
it difficult for Lucid's implementation to use it directly.



          To what end specify the macro expansions exactly?

Some of the more questionable items of development in the Jan 1989 
version of this part of the MOP proposal apparently have been deleted; 
in particular, excessive use of Lisp code as actual specification, and 
a nearly impossible concern for "compilation environments".  As we have 
subsequently come to realize, the "compilation environments" issue is 
not at all a problem unique to CLOS, or to CLOS metaobject protocols, 
since the compiler committee has addressed it in the context of any 
toplevel definer macro such as DEFUN, DEFMACRO, DEFCLASS, DEF<mumble> 
and so on [albeit, with basically very little change from the previous 
state of underspecification, which is actually good, since it allows 
implementations to do "special processing" on DEFUN without detracting 
from the user's ability to write his own, portable expansions of DEFUN-
like definer macros.]

But there are still several serious problems with trying to be specific
about the CLOS defining macro expansions.  First off, it has nothing
to do directly with a metaojbect protocol; for this, we need a clear
definition of a functional interface to metaobject creation and
manipulation, along with the explicit items in the initialization
protocol for classes and generic functions.  ENSURE-GENERIC-FUNCTION, 
ENSURE-CLASS, and ADD-METHOD are steps in the right direction; we
will also need the statement of what initargs are defined for 
creations in the basic metaobject classes.

A comparison can be made with the ordinary function protocols.   What's 
important for defining functions are clear semantics for LAMBDA, BLOCK, 
SETF of SYMBOL-FUNCTION, SETF of MACRO-FUNCTION and so on; the actual way 
in which DEFUN and DEFMACRO might expand into them is then obvious, but 
irrelevant.  In fact the current situation is such that they might even 
expand into implementation-specific primitives -- not even using these 
documented facilities at all -- to achieve the defining effect specified 
for DEFUN and DEFMACRO.  But the writer of portable code is guaranteed
that these "documented facilities" are completely adequate for making 
definitions in the portable language.

Rather, I think the only point of mentioning the expansion of the
definer "user interface" macros is that our experience with metaobject
creations over the past two years, via portable constructs, *had* to
be limited to these macros.  So it's natural that we would tend to think 
of the issues involved in terms of the exterior interface syntax.  Some 
of you who have been on the Common-Lisp-Object-System mailing list for a 
long time may remember that precisely this question arose several years 
ago.  And someone (who? maybe Dave Moon) suggested that while we indeed 
needed the functional interface for class, method, and generic function 
creations, the predominate usage by end users would be in terms of the 
succinct definer macros like DEFCLASS and DEFMETHOD.  Thus we *had* to 
have syntax and semantics for these macros defined in the basic document; 
but the definitions for the functional interface, while logically more 
primitive, could be  postponed until the metaboject layer became more 
fully defined.  Indeed the need by an end-user for the functional layer 
would only really come into play when his application became involved in 
"meta" manipulations.

Sample usages of the basic functions, such as ENSURE-CLASS and 
ENSURE-GENERIC-FUNCTION, are indeed appropriate to have in the language 
specification, to show how one can create whatever class or generic 
functions he wishes *** using only the functional interface.  But 
detailed specification -- in terms of required language specification -- 
of these expansions serves no more purpose to CLOS than explicit coding 
of a DEFUN macro expander would serve for Common Lisp in general.  

Incidentally, since the time of release of the "Rainy Day" PCL, I have 
privately praised the development in it of the class creation protocol,
whereby most all of the old ADD-NAMED-CLASS functionality is distributed
out to methods on the regular initialization protocol functions.  Proof
of the effectiveness of this is your (Gregor's) reply to someone on the 
PCL mailing list about how to make an incremental change in a class's 
superclass and subclass links -- instead of having to re-fetch the parts
of a class definition and cons up a new DEFCLASS macro for for EVALuation, 
why, a rather trivial call to REINITIALIZE-INSTANCE now does it.  This is 
precisely what end-users are looking for in a metaobject protocol; and
we all await with bated breath your and Jim's delineation of this part.

Notice also how two question raised during the past couple days about
this proposal would be re-cast had the proposal been oriented towards 
the specification of functional interface rather than towards the
particular code expansion of the macros.

  (1) Someone asked whether or not the ordering of the items in the
      "plist" type arguments to ENSURE-CLASS was preserved from the
      ordering in the user's DEFCLASS form.  But the real issue is
      whether or not the ordering in the plist makes any difference
      at all to the action of ENSURE-CLASS; if so, then the effects
      of that ordering must be specified.

      Now, *if* ordering does make a difference in any of these 
      "plist" type arguments, then the actual effect that ordering
      has can be documented for ENSURE-CLASS as well as for DEFCLASS.
      Without ever *requiring* that DEFCLASS expands into a call
      to ENSURE-CLASS, we have parallel specifications that in the
      vanilla case would _adquately_ constrain any proposed macro
      expansion of one into the other.

  (2) There have been several questions about how the initforms for
      slots and for default-initargs are handled.  I found the actual
      wording to be very confusing because it used terms like
      "evaluated one or more times"; but in fact what we all know to
      be going on is that the actual form is "effunctuated" precisely 
      once (I believe that is Moon's terminology) , and then that
      function is "executed" zero or more times.   EVAL is certainly
      irrelevant, but I noticed question or two wandered off into the 
      (irrelevant) difference between evaluation of a macro and 
      compilation of it.  [I could give explicit pointers to these 
      email conversation fragments to anyone who wants toe examine
      them further.]

      Now, if the functional interface specifies a function object
      as one of the arguments (or as part of a "plist" argument)
      that almost guarantees that the macroexpansion will have
      turned some <initform> into (FUNCTION (LAMBDA () <initform>)),
      but we need never get bogged down by trying to write a detailed
      specification for the actual code expansion.  Furthermore, even
      if, yes even if, some implementation elects to use a non-portable
      (but more efficient?) construct in its actual expansion of
      DEFCLASS, still one is not precluded from using the FUNCTION
      form listed above in portable code.




    A gap in the current definition of ENSURE-GENERIC-FUNCTION?

I must apologize for the following paragraphs;  I'm certain that a 
problem is there, but I've not put the time into stating it more 
carefully than you can see below.  It is related to Danny's comment:

  "reduced to a g-f lambda-list"  is not defined here or in Chapter 1 or
  2.  If a method has a keyword argument, is that keyword one included in
  the generic function lambda-list?  In the example on page 3-8, not only
  is there no  &key color, but there is not even the &key in the
  lambda-list in the call to the ensure-generic-function.

Also, Moon's comment on the same sentence indicates that he must have a 
similar trouble with it.  As I will be out of town for about a week 
beginning tomorrow, I will not be able to read replies to this msg, nor 
make comments during that time.  But I trust and hope that Moon and 
Cyphers have discovered the same difficulty independently, and will 
explicate it more thoroughly.

I found in implementing the congruency rules that a single :lambda-list
argument wasn't good enough to distinguish the case of "ensuring"
the generic function de novo, and "ensuring" it on subsequent method
definings.  Basically, the call to ENSURE-GENERIC-FUNCTION from within
DEFMETHOD needs the exact method-lambda-list, and needs to know that it 
is a method lambda list, so that it can do something slightly different 
in the two cases (i.e., "de novo" and subsequent).  The suggestion
about reducing the method lambda list to a g-f lambda list makes sense; 
but it just isn't good enough for the two cases.  And of course explicit
_user_ calls to ENSURE-GENERIC-FUNCTION want to specify exactly the g-f 
lambda list -- not some hypothetical method-lambda list that has to be 
reduced.

The difficulty probably comes from the overloading of 
ENSURE-GENERIC-FUNCTION to serve both as a user-level defining function 
for Generic-Functions, and as a last-minute patch-up tool which must try 
to infer an implicit generic-function lambda-list at first method 
definition time, when the user hasn't done a DEFGENERIC before the first 
DEFMETHOD.  As a result, Lucid's implementation has both the functional
entry underlying DEFMETHOD and the function ENSURE-GENERIC-FUNCTION call 
another internal function, which explicitly has a keyword for the case
of a method-lambda-list.




-- JonL --