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

Compilation dependencies in CLOS

You ask some very good questions, Larry, I hope they will be remembered
when the X3J13 proposal is sent out for public review.

-- Concering the phrase of CLtL/2e "the compiler "may also assume that 
    a class defined by DEFCLASS in the compile-time environment will be 
    defined in the run-time environment in such a way as to have the same 
    superclasses and metaclass." 

I think you are right in saying that, taken to the extreme, this is an
untenable constraint.  But I vaguely felt that the tenor of the X3J13
group was that this was a miminal requirement that at ***load-time***,
as opposed to the full duration of run-time, the class would be defined
as described.  

It probably didn't get said very well in the X3J13 documents, and hence 
probably not very well in CLtL/2e, because there was hope by some folks 
that we could all agree on what a "virtual compilation environment" should 
mean.  When the compiler would encounter a DEFCLASS in a file, it would 
effectively "evaluate" that form in the virtual environment set up to 
represent the ultimate runtime image; but it would not evaluate the form 
in the top-level environment of the compiler's image.  The reason for such 
a plan is somewhat akin to the cross-compilation problem -- that you don't 
want the mere act of compiling a file that happens to contain definitions 
contradicting those in the running image to destory that compiler's running 

So "virtual environments" didn't make it.  But thinking about them
apparently diverted some energy that might otherwise have been spent 
clarifying paragraphs like the one you quote above.  Incidentally, the 
problem is not limited to DEFCLASS; I think it may not be so easy to 
ascertain whether the compiler, when encountering a top-level DEFMACRO 
in a file:
   (1) must evaluate the defmacro form, possibly "un-doing" the definition 
       at the end of the compile-file (or "compilation unit") scoping;
   (2) must NOT evaluate the defmacro form;
   (3) must NOT evaluate the defmacro form, but MUST make it available
       for macroexpansion in subsequent code to be compiled in the file;
   (4) choose exactly one of (1), (2), or (3);
   (5) none of the above.

-- Concering the phrase of CLtL/2e: "Any accessors specified by 
    WITH-ACCESSORS must already have been defined before they are used."

I think "used" means "actually called, at runtime"; it doesn't mean the 
more fearsome "referenced by previously processed code".  By analogy, any 
function automatically generated by a :writer slot option must be
defined before it is used.  Now, in my opinion, this restriction is
too trivial to be worth mentioning; and as your extensive critique 
shows, it even seems to be misleading.

-- Concering your question: 

      A third difficulty I have is with the use of undefined classes.
      Consider a DEFCLASS which in its superclass list includes a name
      not yet defined as a class; or a DEFMETHOD which has a parameter
      specializer name that is not yet defined as a class.  Can/Must a
      CLOS implementation permit such references to undefined classes?

88-002R, page 2-24 states that an implementation must allow "forward
references" in other class definitions.  However it also says that a class 
must be defined before it may be "used" as a parameter specializer in a 
method.  Effectively, this means that a DEFMETHOD may not be evaluated 
until all its specialized classes are (fully?) defined.  Note that the 
compiler can compile top-level calls to DEFMETHOD without evaluating them.

-- Concering your question: 

      What operations (e.g., FIND-CLASS) are legal on a
      "forward-referenced class"?  When such a class is later defined
      via DEFCLASS, are all previous references guaranteed to work
      properly without recompilation?

The only "previous references" that could exist are in the superclass
lists of other class definitions.  A metaobject protocol would permit
some way of finding out whether or not a class was "fully defined",
meaning none of its direct superclasses are "forward" references, and 
all of its direct superclasses are themselves fully defined.  But alas
we didn't get that part of CLOS into the spec -- not even into the
"de facto metaobject standard" proposal that Dave Moon and I worked up 
earlier this year, and which was sent out to selected mailing lists as:
    Date: Sun, 4 Mar 90 18:28 EST
    From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
    Subject: Proposed de facto standard subset of metaobjects
    To: Common-Lisp-Object-System@MCC.COM
    . . . 

However, I did raise just this question to the X3J13 community back
in January [and there were no electronic replies, but several verbal
replies saying that FIND-CLASS shouldn't "find" forward references]:

    Date: Wed, 10 Jan 90 05:12:51 PST
    From: Jon L White <jonl@lucid.com>
    To: x3j13@sail.stanford.edu
    Cc: cl-cleanup@sail.stanford.edu
    Subject: FIND-CLASS for "forward-referenced" classes?

    Should FIND-CLASS find a "class" that has only been mentioned in a 
    forward-referenced way, as a direct-superclass of a non-finalized class?
    Does the name of such "class" constitue a valid type-specifier?  E.g., 
	    (defclass FOO (BAR) (a b c))
    defines a non-finalized class named FOO, but does it define one named BAR?

    Chapters 1&2 of the CLOS specification do not specify how one should
    arrange to make "forward" references to superclasses work.  Chapter 3
    suggest somewhat indirectly an implementation technique of actually
    creating a class object, to use as a stub, for such a reference.  But
    there seems to be no requirement that it must be implemented this way;
    some implementations do it this way, and some apparently just keep
    around internal lists of the class names that were referenced in a
    "forward" way.

    Arguing against letting FIND-CLASS return a forward-referenced-class
    object is that the existence of such an actual class-object is merely an 
    implementational artifact, and may not even be portable.  From a larger 
    point of view, one could ask why the mere mention of a potential class
    named BAR, when defining the class named FOO, should give any legitimate 
    definition for BAR; certainly when you make a forward reference to a 
    function name, you don't define that funcion; i.e.
    will define FOO, but not define BAR.

    Arguing for letting *something* find the forward-referenced class is
    the fact that when using the metaobject protocols in an implementation
    that supports forward references this way, you will eventually want a
    handle on the actual object.

    Finally, it must be asked, what is the behaviour of the type system on 
    non-finalized classes (i.e., classes which have some direct, or even 
    non-direct, superclass that hasn't been defined yet).  Clearly, TYPEP is 
    moot, since you can't make instances of non-finalized classes.  But what 
    about subtypep?  The answer for non-finalized class names probably should 
    be consistent with the answer for forward-referenced class names.

    One possible alternative is simply to say that the class names (or class 
    objects too) don't become valid type specifiers until the class is fully 

-- Finally, concering your worry:  "... will I be offered two modes, 
    a 'development' mode that supports compilation independence but 
    generates poor code and a 'production' mode that generates efficient 
    code but imposes onerous compilation dependencies?"

Well, the *hope* of some of the X3J13 members was that there would be
vendors who would offer you that choice.  As far as I know now, no
commercial vendor is actually planning to do so.  There was a VERY
interesting research paper presented at the last CLOS workshop (in
conjunction with the 1989 OOPSLA conference in New Orleans) by a guy 
from Coherent Thought; they had essentially done the "production" mode 
version of CLOS -- at least as far as their application was concerned -- 
and the overall speed difference was only 25%.   Disappointing.  That
isn't to say that there isn't *some* benchmark to be found that wouldn't
show a factor of 3 to 5 speedup by this kind of technology, but that
this one naturally occuring application wasn't greatly affected by it.

-- JonL --