[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
user interface macros
- To: gregor@parc.xerox.com
- Subject: user interface macros
- From: Jon L White <jonl@lucid.com>
- Date: Fri, 27 Apr 90 17:08:50 PDT
- Cc: mop.pa@Xerox.COM
- In-reply-to: Gregor J. Kiczales's message of Mon, 23 Apr 90 21:37 PDT <19900424043758.2.GREGOR@SPIFF.parc.xerox.com>
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 --