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

Re: Constructors

After reading through Moon's well thought out and well articulated
proposal for constructors, I have two comments. The first is syntatic,
the second semantic


The syntax of the DEFCLASS form is already fairly complex, and adding
an additional option will add yet another construct to this special
sublanguage. If constructors are to be added at all (and see the next
section for arguments why they shouldn't be), then I think a smoother
integration would be to add them as a full fledged form, say
DEFINE-CLASS-CONSTRUCTOR. The advantage of this over having a
class option are that the implementation of the constructor (in the
form of code) is locally close to the declaration of the association
between the constructor name and the class name. In the case
of a class option, the association between a constructor name
and a class name is made in the DEFCLASS form, but the constructor
must actually be defined in a seperate form, as a method or function. From the
point of view of someone reading the code (barring comments, of
course) the fact that a particular method is a constructor is
only apparent if they look back at the DEFCLASS form.  I think the advantages
of grouping the definition of the constructor and the declaration
of the association between the constructor name and the class
name outweigh having the class definition and the constructor name
locally close.


To motivate the following discussion, consider that constructors are
added to the language, and the following code is written using them:

	(defclass udc () (a b c) (:constructor udc-cons))

	(defun udc-cons (a b c)
	  (list a b c))

	(defmethod doit ((self udc))

	  (format T "In DOIT for UDC...~S~%" self))

	(defmethod doit ((self list))

	  (format T "In DOIT for LIST...~S~%" self))

	(setf obj (udc-cons 1 2 3))

	(doit obj)

What happens? Is OBJ a LIST or a UDC? Since it is not possible to
subclass the built-in classes using the default, system supplied
metaclasses, it cannot be both. Either the structure of a UDC
instance is more than a list (meaning that the constructor code,
as written, must be augmented to add some hidden state), or we have 
a semantic ambiguity which must be resolved arbitrarily.

The philisophical side of this has to do with how I'd like to
think we want to encourage people to think about the metaclass
protocol. The way I see it (and I may be wrong), among other
things, the metaclass controls the underlying representation of
an instance. Users defining classes should be encouraged to 
think about their classes in a more abstract way, and not have
to be concerned about the representation. If they are concerned
about the representation, then an ALLOCATE-INSTANCE method can
be written to control it. It's the job of the compiler writer
to be sure that the default allocation is efficient enough so that
people are encouraged to use it. Considering that the metaclass protocol
is still in the draft stage, it's a bit difficult to argue cases,
but I think the above example could be resolved by writing a new
metaclass which does let you subclass one of the built-in classes.
It may be a lot of work, involving defining new generic function
and method classes as well.

The optimization considerations outlined in the proposal are certainly
of concern, especially for conventional hardware, but, as the example
indicates, adding constructors could lead to having to add code to
method dispatch to resolve ambiguities (or catch them as errors).
Since method dispatch is THE critical item as far as optimization 
is concerned, it seems like adding constructors would be a case
of robbing Peter to pay Paul. Of course, as was pointed out in the
proposal, this makes the job of the compiler writer more difficult,
if special cases for MAKE-INSTANCE are to be caught and optimized.