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


This is an extract from a much longer comment on CLOS Chapter 3.  I'm
sending this part to cl-compiler since some people who read that may not
be on CLOS mailing lists.



2. Expansion of the User Interface Macros

In general I have problems with what is specified as occuring at compile-time,
specifically with regard to evaluations which are specified as occuring then.
I'll bring up specific points in discussion of each of the defining macros
individually.  It seems to me that to do things in just the way you have
specified, either these macros must side-effect the running system, or you
need EVAL to in some fashion take an environment argument.  I don't believe
the former is acceptable, and the latter is a very big change, and not likely
to occur anytime soon.

Also, for each of the defining macros you include the following paragraph.

  [Note:  Implementations are free to pass additional keyword arguments to
  the underlying generic functions provided those keyword argument names are
  not in the keyword, lisp, or user packages.]

I think it would be better (and more consistent with recent cleanup proposals)
to change this to say that the additional keywords may not be in the user
package or exported from any package specified by the standard.

2.1. Defclass

You are requiring that the form which creates the initfunction be evaluated
at compile-time.  This seems totally inappropriate to me.  It must be
arranged that the form which will return the initfunction will be evaluated
in the proper environment at load-time, but this does not require evaluation
at compile-time.  The only reason for creating the initfunction at compile-
time is if you are going to call it, and in general that isn't possible, since
it may reference things which won't be around until load-time.

Here is a rough outline of what I would expect the example defclass to expand

  (eval-when (compile)
    (ensure-class 'position
      :metaclass (find-class 'standard-class)
      :superclasses (list (find-class 'graphics-object t ',<env>))
         (list (make-instance 'standard-direct-slot
                      :name 'x
                      :initform '0
                      :readers '(position-x)
                      :writers '((setf position-x))
                      :type 'integer)
         (list (list ':screen '*position-screen* nil))
      :environment ',<env>)
  (ensure-class 'position
    :metaclass (find-class 'standard-class)
    :superclasses (list (find-class 'graphics-object))
       (list (make-instance 'standard-direct-slot
                    :name 'x
                    :initform '0
                    :initfunction #'(lambda () 0)
                    :readers '(position-x)
                    :writers '((setf position-x))
                    :type 'integer)
       (list (list ':screen '*position-screen*
                   #'(lambda () *position-screen*))))

A restriction which may not be immediately obvious to everyone that results
 from my view of how this should work is that a class needs to be fully defined
before using it as a :metaclass option to defclass.  Basically, metaclasses
should be in a seperate file from the classes which use them, and that file
must be loaded before the using classes can be defined.  I don't believe that
this is particularly onerous, since I don't view a metaclass as consisting of
just the class object.  It also includes the associated metaobject protocol,
as defined by the set of applicable methods, and these methods can't be
called until they have been 'loaded'.

2.2. Defmethod

Again, you are requiring what I consider inappropriate evaluation at compile-
time.  Specifically, I don't believe you should be evaluating the eql
specializer form.

Also, it isn't clear to me that it should be necessary to actually create a
method and call add-method at compile-time.  I suppose the information gained
by doing so could be used to sometimes optimize away method lookup at compile-
time.  But the inability to properly add eql-specialized methods under some
conditions makes this somewhat dubious to me.  It would seem more appropriate
to figure out such things at load-time, possibly by doing things like
transforming method-lookup into an array-access or some such thing.  Another
problem with doing such things at compile-time is that it requires that you
be able to do the method combination at compile-time, which would require the
same kinds of restrictions as I've suggested for metaclasses, ie. seperate
compilation of the define-method-combination.

Actually, another point for calling add-method at compile-time is that that
is probably when the lambda-list congruency test is performed.  However, that
could be extracted out and done seperately at compile-time.

2.3. Defgeneric

Processing the :method options has the same comments as defmethod above.

2.4. Define-method-combination