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

Re: Name That Class

I said: 
Date: Tue, 11 Aug 87 16:01:12 MST
From: kempf@hplabsz

>> 2) Have the name to class object binding for an entire class be handled
>>    by the metaclass protocol. 

Moon replied:

> I don't understand how this could work.  If one is given a class name and
> one wants to find the corresponding class object, how do you know what
> metaclass is relevant before you have found the class object?

and Gregor said (somewhat earlier):

>Even if we decide that class-name should return at most one name, I
>think it is clear that a class can have more than one name.  That is,
>it is legal to use setf of symbol-class to make the multiple symbols
>point to the same class. 

and Patrick said (even earlier):

>The environment argument will be necessary to address the compile
>environment problem.  The term might be confusing, it is not necessary
>an environment like the &environment argument in a macro definition.

I've been rethinking this issue somewhat, and I think we need to consider
how class names will be used. I can see three ways in which
users may need to use class names:

1) In inheritance lists for indicating direct supers,
2) In parameter specializer lists for indicating that particular method
   parameters are specialized to particular classes (or their subclasses),
3) For instantiation,
4) For general queries (i.e. system building-"Is this class there?", etc).

There will be more reasons for using class names if metaclass programming
is taken into account. Let's just consider these for the moment and ask
what would happen if a many to one mapping of classes to names (and
vice versa) were allowed.

If multiple names were allowed to be "bound" to a single class object,
then the function CLASS-NAME(S) could potentially return a list.
The function SYMBOL-CLASS (or CLASS-NAMED) could also return a list,
since, for any particular name, there could be multiple class
objects having it. That is, if we have FOO1 and FOO2 bound to two different
class objects, and the following is legal:

	(setf (class-name foo1) 'baz)
	(setf (class-name foo2) 'baz)

then the following:

	(symbol-class 'baz)

should return a list with two elements, with the CAR EQ to FOO1 and the

What would this mean for user code? For one thing, the following would be

(defmethod doit ((x baz))

since there are now two possibilities for the class BAZ. One could argue
that this should mean that the method should be selected if X is
from either class, but that would be expanding the kind of parameter
specializer to boolean selection, and users may begin to demand something

(defmethod doit ((x (or foo1-class foo2-class)))

which we may want to avoid. Of course, we could always demand that the
user put in the class object directly, to disambiguate, but names are
good for *something*, in this case, as a shorthand for not having to
say something like:

(defmethod doit ( (x (cadr (symbol-class 'baz))) )

The reason classes are different from functions is because function
definition objects don't have settable names. You can't say:

	(setf (function-name fundef1) 'foo)
        (setf (function-name fundef2) 'foo)

at least, not in portable Common Lisp (most implementations probably 
allow this sort of thing internally). In addition, the inverse mapping 
to SYMBOL-FUNCTION (from function definition objects to names, called 
FUNCTION-NAME in the above example) is not defined.
With classes, the inverse mapping needs to be defined and settable, and 
that is what is compilicating the issue. There are ways to hack around it,
designating one name the principle name, etc., but they all introduce more 
machinery that I think most users will want.

Metaclasses could be used to allow multiple names per class only if
the name to class binding were restricted to one to one within a metaclass.
Across metaclasses, multiple names per class could be allowed.
The various ways this would affect the programmer interface are as follows:

1) SYMBOL-CLASS would require an optional metaclass argument, which
would default to STANDARD-CLASS. SYMBOL-CLASS would be used for general 
queries, in addition.

2) Inheritance lists would be no problem, since supers must be of
the same metaclass anyway.

3) DEFMETHOD would require additional machinery to specify the metaclass
of the parameters. Possible choices are:

  a) A DEFMETHOD option specifying that the parameters must be
     from a particular metaclass. This will give problems with
     mixing specializers, for example, if specializers of 
     metaclass STANDARD-TYPE-CLASS are mixed with those of
     metaclass STANDARD-CLASS, as is likely.

  b) The syntax of specialized lambda lists be expanded to include
     some means of indicating that the class is of a particular
     metaclass. This is more flexible, but syntatically clumsier.
     Something like:

	(defmethod doit ((x foo nonstandard-class) y x)

     is what I have in mind. Defaulting to STANDARD-CLASS may help.

  c) DEFMETHOD only works with parameter lists whose classes
     are from a restricted set of metaclasses. STANDARD-TYPE-CLASS,
     and STANDARD-CLASS are obvious candidates. A user wanting to 
     handle parameters of another metaclass would need to write
     their own parameter list parser, and their own top level macro.

4) Instantiation via. MAKE-INSTANCE would require either:

  a) An optional metaclass argument, 

  b) The argument would need to be the class object itself
     rather than a symbol, 

  c) A symbol argument could default to STANDARD-CLASS.

I honestly think that even this is more machinery than most applications
programmers are going to need. Most users are simply going to use the
default metaclass, and won't want to have more than one name per class
or more than one class per name.

But, as Patrick has pointed out, the issue is more complex. The name
to class (or name to generic function) binding has an additional component,
namely the environment. What I think we *really* want is a way to have
the name to object binding be dependent on the environment as well.
This issue is more important than the issue of user level multiple
names per class (even for metaclass programming) since it directly
affects implementations which can't use virtual memory to segment
processing steps, and could adversely affect bootstrapping in any event.
As I mentioned in a previous note, I think this issue should be resolved
by a comprehensive, well thought out statement about the processing model
for the Concepts chapter. Then, individual functions which require
interface modifications should be modified. As Patrick mentioned in his
note, the environment need not be a CLtL environment; in fact, given
the second class status of environments in Common Lisp, it is hard
to see how it *could* be without some beefing up of what you can do
with them.

I'll leave it at that for this note. Summarizing, my feeling is that
allowing a multiple name per class object binding has some serious problems
for user level code, since the names of class objects are and
probably should be settable. I don't feel offering the functionality
to users is particularly important at this time, but if people want
it, then I think restricting the name to object mapping to be one to
one on a metaclass by metaclass basis is probably the right way to go.
More important is a resolution of the name to object mapping in different
processing environments, and this should probably be done in a comprehensive
manner, including generic functions also.

	Jim Kempf 	kempf@hplabs.hp.com