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

Re: Object Creation Discussion (at last!)



Comments on Moon's creation note (and subsequent discussion):

OVERALL COMMENTS:

I agree with Gregor that the proposal needs simplification. The
special method combination type, the overemphasis on constructor
speed (they could be simply declared IN-LINE) and the complex
rules for lambda-list interpretation need some reworking.

In addition, I would like to see the syntax for the :INITFORM, :INITARG,
and :DEFAULT-INITARG options better integrated (see below for addition to 
Gregor's suggestion).

SPECIFICS:

*On symbols as initarg keys:

>  "initargs" (initialization arguments) are a set of named arguments that
>  control object creation and initialization.  Each initarg has a name, which
>  is a symbol (not necessarily a keyword), and a value.  The arguments to
>  make-instance, excepting the first, taken in pairs, are initargs.

Subsequent discussion has cleared up this point as a potential area
of incompatibility which needs a cleanup committee proposal.

*On storage allocation:

>   Also customizable by the metaclass, because the metaclass controls the
>   stored representation of instances.

This should probably be the "recommended" way of doing things.
Though it's probably not a good idea to prohibit it, I think it
should be encouraged for portability reasons. The metaobject protocol
should be the lowest level, portable interface into the object system.
Anything below should be system dependent.

*On the proposed additional slot and class definition options:

>3. Customizable by slot-description, which specifies a default value for the
>   slot and whether the slot can be filled with a value specified by the
>   client; if so, the slot-description specifies the name of the initarg
>   whose value is stored into the slot.
>The :default-initargs defclass option is followed by alternating initarg
>names and forms.  If an initarg is not specified by the client nor by
>a :default-initargs option in a more specific class, the form is evaluated
>in the lexical environment of the defclass and the resulting value is used
>for the initarg.

From subsequent discussion, it seems as if an additional DEFCLASS
option, :DEFAULT-INITARGS is being proposed. I wonder if this
is needed, considering that a user can already specify an initialization
value via the :INITFORM option? Perhaps the metaclass ought to 
attend to this? Or the :INITFORM and :DEFAULT-INITARGS options should
be merged?

In particular:

>So, a defclass form like this:
>
>	(defclass position ()
>	  ((x :initarg :x)
>	   (y :initarg :y))
>	   (:default-initargs (:x 0) (:y 0) :rho :theta))
>

Consider what the syntax would be if you wanted to specify an initform
as well:

	(defclass position ()
	  ((x :initarg :x :initform 0)
	   (y :initarg :y :initform 0))
	   (:default-initargs (:x 0) (:y 0) :rho :theta))

So why not simplify this as:

	(defclass position ()
	  ((x :initarg (:x 0))
	   (y :initarg (:y 0)))
	   ( <some appropriate key> :rho :theta)
	)

Semantics are:

1) If MAKE-INSTANCE is called without an initialization list,
the initialization values of X and Y are set to zero.

2) If initialization values are supplied in the initialization list,
then they are used.

3) :RHO and :THETA are valid as keys for initargs to MAKE-INSTANCE in
any case. If no value is given, then they are NIL.

A suggestion for <some appropriate key> would be :ADDITIONAL-INITARGS.

*On MAKE-INSTANCE and modules:

>>> Is make-instance an intra-module or inter-module interface?
>
>Both.
>
>>> Do the arguments to make-instance correspond directly to actual stored
>slots, or are they a more abstract concept, whose implementation in terms
>of slots or in terms of something else is hidden from the caller?
>
>More abstract, because make-instance is often used as an inter-module

I don't understand. What is understood here by the word "module"?
Has it any relation to *MODULES* on pg. 188 and thus to the
PROVIDE/REQUIRE mechanism?

*On constructors:

>>> What is the lambda-list of a constructor created by a :constructor
>option with no lambda-list specified?
>
>It accepts the same arguments as make-instance, excepting the first.
>
>>> Do constructors call initialization methods?
>
>Yes.
>
>>> Why do we have a :constructor option to defclass?
>
>For speed; make-instance is interpretive, while constructors are compiled,
>since they know the exact class that they are constructing, and since they can
>be automatically recompiled if the class or any of its superclasses changes.

I'm not quite sure how this fits in with the metaclass protocol.
What if a user defines a constructor function to make an object out
of a list, or to return a symbol? If the constructor function tries
to call initializaton methods, then what will be the result? Also,
if the initialization succeeds, method definition and lookup might
do the wrong thing if the low level structure of an instance is
not what is expected. As an example, say the constructor function
returns an integer, and there are two methods on a generic function,
one with an INTEGER selector and one with the same class as the
erring constructor function. 

In addition, I think the IN-LINE declaration could help getting speed
out of a constructor.

*On the context in which an initialization is run:

>The :initarg slot-option specifies that this slot can be filled in, and
>specifies the initarg name.  This slot-option can be given more than once.
>
>There is no defclass option that specifies initargs for all the slots,
>because that would endorse a particular convention for naming initargs.
>

Are the initforms run in the context of INITIALIZE-INSTANCE? Is WITH-SLOTS
acceptable within an initform?


I think this proposal would satisfy Dave Martin's request for initialization
hooks. I'm enclosing his message on this below.

	jak

---------------------------------------------------------------------------

Well, what we currently have is the following:

defmethod initialize ((self new-object) init-plist)
	(initialize-from-defaults self)
	(initialize-from-init-plist self init-plist)
	(apply #'new-instance self init-plist))

Where the new-instance function is defined to do nothing for new-object but
takes an arbitrary list of keywords (generally including slot names) to
set the values.

What I would *like* to see is the function initialize (or some other name)
initialize from the defaults, and then initialize from the init-plist only
on slots keywords (this is what we do, I rewrote initialize-from-init-plist
to ignore non-keyword slots) and then call a class specific function to
do the remaining setup.  It would be nice if slots which were read-only
were still settable inside the initialization code (e.g. the resource id of
a window object should be read-only, but I can't set it until the new-instance
function is called).

I was thinking about changing the initialize function to do the following:
1) initialize from the default value of each keyword slot; 2) use the setf
function for setting from the init-plist argument for any keywords which 
correspond to slots; and 3) call a user-specifiable routine (i.e. have a slot
in the class called initialize-method) which would be mandatory for each class
and would be hacked to allow call-next-method to find the appropriate method
for the super classes even if the method name differed.

With this setup we avoid having to set aside new-instance as a reserved 
name, allow the system to set slot values appropriately (using the setf method
should be a flaggable option), and hopefully be able to reduce the size
of the new-instance function.