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

remote environments



    Date: Thu, 23 Feb 89  18:38:01 CST
    From: David N Gray <Gray@DSG.csc.ti.com>

    I think it might help to focus the discussion about remote environments
    and meta object programming if we had a clearer picture of what the
    goals are.  The basic question is what kinds of things can be defined and
    then used during compilation of the same file that defines them, and
    what restrictions might apply.

I think you're right.  Let me offer my opinions on the set of issues
you have articulated.

    DEFCLASS 
      * Can the class be used as a superclass of a later DEFCLASS?  [clearly yes]
      * Can it be used as a specializer in a DEFMETHOD?  [clearly yes]
Agreed.
      * Can a MAKE-INSTANCE be done by a macro expander, DEFCONSTANT, or "#."?

I have two answers to this, both based on current practice but
contradictory.  One is that I have some users who really need to be able
to instantiate such classes in macro expanders.  They have an embedded
language which has an object-oriented representation for programs;
therefore macro expansions include instances of classes defined earlier
in the same file.  The second is that Flavors does not support
instantiation of compile-time classes in the Symbolics implementation,
consequently the users I mentioned are currently operating with a kludge.

I think it would be much nicer if we could make compile-time classes
instantiable.  However, I agree that it would not ruin the language to
omit that feature if we can't figure out how to do it.

	 - If so, do initforms have access to macros and constants defined
	   earlier in the file?

Initforms certainly have access to those things since they are included
in the initforms' environment.  I think 88-002R implies this.

      * Can the class be used as the :METACLASS option of a later DEFCLASS?
	 - Can that second class be instantiated?
      * Can it be used as the :GENERIC-FUNCTION-CLASS option of a
	DEFGENERIC, GENERIC-FUNCTION, GENERIC-FLET, or GENERIC-LABELS?
      * Can it be used as the :METHOD-CLASS option of a DEFGENERIC etc.?
	 - Can DEFMETHODs then be done for that generic function?

The answers to these three should be the same and should depend just on
whether a remote (aka compile-time) class can be instantiated.  If yes,
then the subsidiary questions are clearly also yes.

    DEFGENERIC
      * Referenced by later DEFMETHOD? [clearly yes]
      * Is the function defined such that it can be called at compile time?

Clearly not, since a DEFUN is not.  Here I think we should defer to the
definition of how COMPILE-FILE deals with DEFUN and not try to propose
something "better" that is just for CLOS.  In fact I do have something
better in mind, in which COMPILE-FILE would be less different from
normal Lisp evaluation.  But I don't think it would be appropriate to
propose something so radical for Common Lisp at its current life stage.

    DEFMETHOD
      * Can it be invoked at compile-time?
      * In particular, will methods added to standard generic functions be
	invoked by the system at compile time?

No, and no, for the same reason.

When you compile-file a DEFMETHOD, a method metaobject is created but it
is not added to the generic-function metaobject in the local environment.
Instead it is added to a different generic-function metaobject created
in the remote environment.  That's my model of what has to happen.  Note
that this should be completely consistent with the way that compile-file
of a DEFCLASS, with a direct superclass whose name is defined in the 
local environment and not in the remote environment, does not add the
new class metaobject to the direct subclasses of the local superclass,
but rather to a different object.  (I realize we haven't agreed on what
this paragraph says, or even seen a coherent proposal, yet.  I'm just
telling you my model.)

    DEFINE-METHOD-COMBINATION
      * Used in a later DEFGENERIC?
	 - Callable at compile-time?

I believe this should be yes to both, although if I'm not mistaken
Flavors does not allow it.  I think that's a bad design choice in
Flavors.

    Are there other interactions that need to be considered?

I can make a few other points.  Assuming remote classes can be
instantiated, remote methods specialized to a remote class of course
cannot be executed.  However, nothing stops us from making a local
method specialized to a remote class.  There happens not to be a
defmethod syntax for doing that [although in fact one could imagine
such an extension], but it should be easy to do with the interface
at the next level down.  That's a benefit from the clear separation
between names and objects for which CLOS is striving.

In the past there has been some controversy about whether the remote
environment can inherit from the local environment.  I think this is
crystal clear: since some user-defined classes have STANDARD-OBJECT
as a direct superclass, and STANDARD-OBJECT is not defined in the same
file, the remote environment is clearly inheriting from the local
environment.  Different implementations might want to address the
details of this differently, but I think it's clear that there has to
be provision for it in the metaobject model.  It makes things more
complicated, but that's unavoidable.

    I think that the standard could take a simple, minimal, approach that
    would still satisfy the most common usages.  Suppose we said:

    DEFCLASS
      If it appears at top-level, then the class name is defined for use as
      a type specifier or method specializer.  It can also be used as a
      superclass of a later DEFCLASS since they don't have to be defined
      before being referenced anyway.  The class object can be obtained by
      calling FIND-CLASS with an environment argument, but it can only be
      used in ways that do not require the class to be finalized.  For
      example, one could ask for its CLASS-DIRECT-SUPERCLASSES, but not its
      CLASS-PRECEDENCE-LIST.  Other uses, which could involve the need to
      instantiate the class, could not be portably done in the same file
      without wrapping an (EVAL-WHEN (EVAL COMPILE LOAD) ...) around the
      DEFCLASS.  Implementations would be free to support compile-time
      instantiation as an extension.  One way to look at this would be to
      say that it is implementation-dependent whether FINALIZE-INHERITANCE
      works or signals an error when given a class defined in the
      compile-time environment.

    [And no compile-time generic-function or method objects at all]

This is an interesting idea, but I think it's too restrictive.  Here's a
plausible and many-times proposed application for metaobjects which
would not be possible if we adopted this idea.  Suppose you made an
optimizing compiler that is allowed to assume that no class
redefinitions, no method redefinitions, and no newly-defined subclasses
will be created at run time.  The compiler is to take advantage of this
constraint on the program to generate more efficient code by doing type
propagation and constant-folding out many method lookups and slot
lookups.  One should expect many CLOS programs compiled this way to have
the same efficiency as C++ without suffering the same restrictions
during development.  Now, the natural way to organize the datastructures
in this compiler is as metaobjects.  CLOS (chapter 3 at least) already
defines how to access the information the compiler needs.  The
constraint against run-time redefinition means the compiler can assume
certain functions of metaobjects return the same result at compile time
as they must at run time.  For this to work all the metaobjects must
exist and finalization must possible.  It doesn't appear that
instantiation is required, assuming the program being compiled doesn't
define any metaclasses.

I hope to keep thinking in this direction.