rather than treating them like metaobject or
argument-precedence-order? could someone who was party to the
deliberations shed some light on this?
thanks,
...
james anderson wrote:
> rather than treating them like metaobject or
> argument-precedence-order? could someone who was party to the
> deliberations shed some light on this?
I don't know, but check out ftp://ftp.parc.xerox.com/pub/pcl/archive/ -
it contains the archive of the CLOS and MOP designers' mailing list.
Maybe you can find some rationale there.
BTW, what do you mean by "metaobject" in this context? metaclass is also
persistent AFAICS.
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
james anderson wrote:
> why does the mop handle default-initargs as persistent,
> rather than treating them like metaobject or
> argument-precedence-order? could someone who was party to the
> deliberations shed some light on this?
on the info-mcl list, James Anderson wrote:
>
> i posted yesterday a note to c.l.l., to enquire whether anyone understood
> why properties like default-initargs were treated as persistent across
> defclass evaluations.
That is a different question, and I am not quibbling: whether to
conflate the MOP spec on ensure-class-using-class with the behavior of
defclass is where implementors have differed. Franz here on c.l.l. has
cited the MOP on ensure-class as justifying AllegroCL's defclass
behavior, what you call default-initarg persistence. I called it
"stickiness" in threads in 99 and jan '02.
For my money, this simple sentence from the spec (4.3.6) settles the
second question:
"Redefining a class modifies the existing class object to reflect
the new class definition; it does not create a new class object for the
class."
Adopting your word, persistent default-initargs across defclass
evaluations violates the first half of that sentence. Unfortunately, the
point of that sentence was whether a second defclass makes a new class
object. So maybe the requirement to "reflect the new class definition"
was just a throwaway line, one not thought thru so deeply as to
constitute an override of the MOP on ensure-class-using-class:
"Unless there is a specific note to the contrary, then during
reinitialization, if an initialization argument is not supplied, the
previously stored value is left unchanged."
But (to rehash my position) that is the spec of one function from the
MOP internals, not a spec of defclass. On the other hand, any reasonable
developer would expect a class indeed to reflect its new definition (as
the spec happens to mandate), so I cannot see why any implementation
would treat:
(defclass xxx ()())
... differently than:
(defclass xxx ()()(:default-initargs))
Well, OK, I can see why: as with two forms of this question cited up
top, the spec of MOP internals is being conflated with the spec of
defclass. Which brings me to this confession: nothing here addresses the
original query about either the MOP rationale or its legislative history.
kt
ps. I might be all wet. You moved the topic to the info-mcl list, but
the last time I used MCL (4.3) :default-initargs was not persistent
across defclass evaluations. So maybe I have totally misunderstood the
issue? k
--
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Kenny Tilton wrote:
> [...] any reasonable
> developer would expect a class indeed to reflect its new definition (as
> the spec happens to mandate), so I cannot see why any implementation
> would treat:
>
> (defclass xxx ()())
>
> ... differently than:
>
> (defclass xxx ()()(:default-initargs))
A reason I can imagine is that you don't know in general what the
default value for an option is. In the case of :default-initargs, NIL is
a reasonable choice, but in the case of :allocation, for example, it's
:instance. The MOP designers had to think of general solutions that work
for all metaclasses, not just ad-hoc solutions that work only for
standard-class. So in order to determine the default values for specific
options they would have had to introduce another protocol that a)
determines all the available options for a metaclass / metaobject and b)
determines all the default values for those options. It seems to me that
they didn't have enough time anymore to work out such details.
An important statement in the AMOP book is this: "This document should
not be construed as any sort of final word or standard, but rather only
as documentation of what has been done so far." (page 135) So I suggest
that discussions about such topics should not treat that text as more
binding than it does itself. The MOP spec has never gotten the same
amount of careful treatment as the rest of ANSI Common Lisp.
There are a number of things that the MOP should specify differently
IMHO. For example, eql specializers are clumsy, slot-...-using-class
should specialize on slot names not on slot definition objects, and
reader-method-class and writer-method-class are too limited. So I guess
that metaobject options and default values are just another open issue.
That's all.
Pascal
--
Pascal Costanza University of Bonn
···············@web.de Institute of Computer Science III
http://www.pascalcostanza.de R�merstr. 164, D-53117 Bonn (Germany)
From: Bruno Haible
Subject: Re: why does the mop handle default-initargs as persistent,
Date:
Message-ID: <chpt53$dm8$1@laposte.ilog.fr>
Pascal Costanza wrote:
>
> slot-...-using-class should specialize on slot names not on slot
> definition objects
CLOS is about creating subclasses in order to realize specific,
different behaviour for some objects.
If a user wants to customize slot access for some specific slots,
i.e. specialize on SLOT-VALUE-USING-CLASS's third argument, the
natural way, completely in line with the CLOS philosophy, is to create
a subclass of the slot-definition class and use this subclass as
specializer in SLOT-VALUE-USING-CLASS methods.
You cannot do this with slot names, since slot names are usually
symbols, and the user cannot create subclasses of the class SYMBOL.
Bruno
Bruno Haible wrote:
> Pascal Costanza wrote:
>
>>slot-...-using-class should specialize on slot names not on slot
>>definition objects
>
> CLOS is about creating subclasses in order to realize specific,
> different behaviour for some objects.
>
> If a user wants to customize slot access for some specific slots,
> i.e. specialize on SLOT-VALUE-USING-CLASS's third argument, the
> natural way, completely in line with the CLOS philosophy, is to create
> a subclass of the slot-definition class and use this subclass as
> specializer in SLOT-VALUE-USING-CLASS methods.
>
> You cannot do this with slot names, since slot names are usually
> symbols, and the user cannot create subclasses of the class SYMBOL.
There are a number of other options in this regard. You can still use
eql specializers. And, of course, you can use specific tests inside the
slot-...-using-class methods.
But that's besides the main point. The main point is that you cannot
implement an, IMHO, important kind of metaclass that allows you to add
or remove slots to objects at runtime. The CLOS MOP only specifies slot
definition objects for slots that are part of the class definition.
In fact, slot-...-using-class were specialized on slot names until very
late in the game, just a few months before AMOP was published. You can
see this in the MOP discussion archive. As an indication, ANSI CL
specifies that SLOT-EXISTS-P is implemented by calling
SLOT-EXISTS-P-USING-CLASS - however, SLOT-EXISTS-P-USING-CLASS doesn't
make sense when you pass a slot definition object because the existence
of a slot definition object already implies the existence of the slot.
As another indication, Section 3.8 of AMOP still reflects the old design.
However, I think there is a middle path. One could specify that
SLOT-...-USING-CLASS is generally implemented like this:
(defmethod slot-...-using-class (class instance (slot symbol))
(slot-...-using-class class instance
(find slot (class-slots class) :key #'slot-definition-name)))
...and then it's possible to use both styles of method specialization.
However, this requires a change of the MOP spec.
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Bruno Haible
Subject: Re: why does the mop handle default-initargs as persistent,
Date:
Message-ID: <chq9uq$4j$1@laposte.ilog.fr>
To my statement:
>> The natural way, completely in line with the CLOS philosophy, is to create
>> a subclass of the slot-definition class and use this subclass as
>> specializer in SLOT-VALUE-USING-CLASS methods.
Pascal Costanza replied:
> There are a number of other options in this regard. You can still use
> eql specializers.
Sure, you can, instead of creating a class that ties together some
objects, write a particular method for each of the objects. But what
do you gain when doing this? Small code size? Maintainable code?
> And, of course, you can use specific tests inside the
> slot-...-using-class methods.
This "alternative" is not only not object oriented, it is even not
extensible!
> The main point is that you cannot
> implement an, IMHO, important kind of metaclass that allows you to add
> or remove slots to objects at runtime. The CLOS MOP only specifies slot
> definition objects for slots that are part of the class definition.
Huh? Every metaclass that is subclass of STANDARD-CLASS allows the
behaviour that you want: You can at any time call ENSURE-CLASS with a
new list of direct slots, and this will modify all your instances.
If you want to add slots at runtime to one object but not the others,
then you need a specific class for each of the objects. (This is
obvious, since the purpose of a class is to describe the memory layout
and operations of a set of objects, called "instances" of that class.)
Note that singleton classes are more frequently seen in Smalltalk than
in Lisp (for no apparent reason).
Bruno
Bruno Haible wrote:
> To my statement:
>
>>>The natural way, completely in line with the CLOS philosophy, is to create
>>>a subclass of the slot-definition class and use this subclass as
>>>specializer in SLOT-VALUE-USING-CLASS methods.
>
> Pascal Costanza replied:
>
>>There are a number of other options in this regard. You can still use
>>eql specializers.
>
> Sure, you can, instead of creating a class that ties together some
> objects, write a particular method for each of the objects. But what
> do you gain when doing this? Small code size? Maintainable code?
I don't understand this remark. How is this related?
>>And, of course, you can use specific tests inside the
>>slot-...-using-class methods.
>
> This "alternative" is not only not object oriented, it is even not
> extensible!
I think it's irrelevant whether you call it object-oriented or not. I
think my suggestion (a default method specialized on slot name applies
itself to the slot definition object) just adds another level of
flexibility, only opens up what a CLOS implementation already has to do
internally, and doesn't negatively affect what was possible before.
>>The main point is that you cannot
>>implement an, IMHO, important kind of metaclass that allows you to add
>>or remove slots to objects at runtime. The CLOS MOP only specifies slot
>>definition objects for slots that are part of the class definition.
>
> Huh? Every metaclass that is subclass of STANDARD-CLASS allows the
> behaviour that you want: You can at any time call ENSURE-CLASS with a
> new list of direct slots, and this will modify all your instances.
I don't want all my instances modified.
> If you want to add slots at runtime to one object but not the others,
> then you need a specific class for each of the objects. (This is
> obvious, since the purpose of a class is to describe the memory layout
> and operations of a set of objects, called "instances" of that class.)
Yes, but I would like my class to be able to choose a hashtable-based
"layout" and be able to add and remove slots at runtime. And I see a way
to add that to CLOS without affecting existing practice. So what's the
problem?
> Note that singleton classes are more frequently seen in Smalltalk than
> in Lisp (for no apparent reason).
They don't have global variables.
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Rahul Jain
Subject: Re: why does the mop handle default-initargs as persistent,
Date:
Message-ID: <87oekar72e.fsf@nyct.net>
Bruno Haible <·····@clisp.org> writes:
> Note that singleton classes are more frequently seen in Smalltalk than
> in Lisp (for no apparent reason).
Singleton classes are usually used as namespaces. Lisp already has
namespaces, so singleton classes are only needed when one needs to
subclass some existing class. What I never understood is what a subclass
of a singleton class was supposed to do. :)
--
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Bruno Haible
Subject: Re: why does the mop handle default-initargs as persistent,
Date:
Message-ID: <ci47fn$bmm$1@laposte.ilog.fr>
> Note that singleton classes are more frequently seen in Smalltalk than
> in Lisp (for no apparent reason).
Actually I think the reason they are rarely seen in Lisp is that Lisp
has EQL specialized methods, whereas Smalltalk only has class
specializers.
Bruno
From: Bruno Haible
Subject: Re: why does the mop handle default-initargs as persistent,
Date:
Message-ID: <chpseb$a5c$1@laposte.ilog.fr>
Kenny Tilton wrote:
> on the info-mcl list, James Anderson wrote:
> >
> > i posted yesterday a note to c.l.l., to enquire whether anyone understood
> > why properties like default-initargs were treated as persistent across
> > defclass evaluations.
The phenomenon is not limited to classes and :default-initargs; it
occurs for
DEFCLASS
:default-initargs
:documentation
DEFGENERIC
:generic-function-class
:argument-precedence-order
:method-class
:documentation
For the MOP functions ENSURE-CLASS, ENSURE-GENERIC-FUNCTION, being
based on reinitialize-instance, it is natural that omitting a property
from the new specification has the effect of keeping the old value.
For the macros DEFCLASS, DEFGENERIC, however, a programmer expects
that executing the new definition erases the old definition; this is
also what ANSI CL 4.3.6 says:
"Redefining a class modifies the existing class object to reflect
the new class definition"
Bruno
Bruno Haible wrote:
> For the macros DEFCLASS, DEFGENERIC, however, a programmer expects
> that executing the new definition erases the old definition; this is
> also what ANSI CL 4.3.6 says:
>
> "Redefining a class modifies the existing class object to reflect
> the new class definition"
You seem to suggest that...
(defclass xyz ()
())
...should expand into...
(ensure-class 'xyz
:direct-superclasses nil
:direct-slots nil
:default-initargs nil
:documentation nil
:metaclass (find-class 'standard-class))
However, what should the following expand to?
(defclass xyz ()
()
(:metaclass my-class-that-has-options-with-non-nil-default-values))
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
Pascal Costanza wrote:
>
> Bruno Haible wrote:
>
>> For the macros DEFCLASS, DEFGENERIC, however, a programmer expects
>> that executing the new definition erases the old definition; this is
>> also what ANSI CL 4.3.6 says:
>>
>> "Redefining a class modifies the existing class object to reflect
>> the new class definition"
>
>
> You seem to suggest that...
>
> (defclass xyz ()
> ())
>
> ...should expand into...
>
> (ensure-class 'xyz
> :direct-superclasses nil
> :direct-slots nil
> :default-initargs nil
> :documentation nil
> :metaclass (find-class 'standard-class))
>
> However, what should the following expand to?
>
> (defclass xyz ()
> ()
> (:metaclass my-class-that-has-options-with-non-nil-default-values))
The same as this:
(defclass xyz ()
()
(:default-initargs)
(:metaclass my-class-that-has-options-with-non-nil-default-values))
I gotta say, I am having a hard time even understanding this line of
argument you are trying to develop. Classes of your imagined metaclass
get metaclass-supplied default-initargs from....where? Perhaps you could
expand your counterexample to include the metaclass and the magic
default initargs.
If a metaclass wants slots to default to zero or t or something other
than nil, it should not be done via the :default-initargs option. that
bad boy is for the defclass author.
kt
--
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Kenny Tilton wrote:
> Pascal Costanza wrote:
>
>>
>> Bruno Haible wrote:
>>
>>> For the macros DEFCLASS, DEFGENERIC, however, a programmer expects
>>> that executing the new definition erases the old definition; this is
>>> also what ANSI CL 4.3.6 says:
>>>
>>> "Redefining a class modifies the existing class object to reflect
>>> the new class definition"
>>
>> You seem to suggest that...
>>
>> (defclass xyz ()
>> ())
>>
>> ...should expand into...
>>
>> (ensure-class 'xyz
>> :direct-superclasses nil
>> :direct-slots nil
>> :default-initargs nil
>> :documentation nil
>> :metaclass (find-class 'standard-class))
>>
>> However, what should the following expand to?
>>
>> (defclass xyz ()
>> ()
>> (:metaclass my-class-that-has-options-with-non-nil-default-values))
>
> The same as this:
>
> (defclass xyz ()
> ()
> (:default-initargs)
> (:metaclass my-class-that-has-options-with-non-nil-default-values))
>
> I gotta say, I am having a hard time even understanding this line of
> argument you are trying to develop. Classes of your imagined metaclass
> get metaclass-supplied default-initargs from....where? Perhaps you could
> expand your counterexample to include the metaclass and the magic
> default initargs.
OK, maybe I haven't been clear enough. The :default-initargs option is
an option understood by instances of standard-class. Other metaclasses
may not accept this option (say, built-in-class) and, that's more
important, again other metaclasses may want additional options. So for
example, the metaclass my-metaclass may want to define a class option
my-option, so that the programmer can say this:
(defclass xyz ()
()
(:my-option 'bla)
(:metaclass my-metaclass))
However, if programmers say this:
(defclass xyz ()
(:metaclass my-metaclass))
...they may want to have this by default be expanded to that:
(ensure-class 'xyz
...
:my-option ... some non-nil form ...)
:metaclass my-metaclass)
The important points here are:
- The default value for some arbitrary class option is not necessarily nil.
- Even if it were nil, what source of information should the MOP use to
determine the acceptable options? Currently, there is none, AFAICS.
- "We" could agree to have an exceptional rule for :default-initargs but
we should be aware that this would only be an ad-hoc solution.
Keep in mind that reinitialize-instance is not the right place to define
nil as a default value for :default-initargs since the functional
interface is supposed to keep unmentioned things as they are. (This is
foremostly a reminder for myself. ;)
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
Pascal Costanza wrote:
>
> Kenny Tilton wrote:
>
>> Pascal Costanza wrote:
>>
>>>
>>> Bruno Haible wrote:
>>>
>>>> For the macros DEFCLASS, DEFGENERIC, however, a programmer expects
>>>> that executing the new definition erases the old definition; this is
>>>> also what ANSI CL 4.3.6 says:
>>>>
>>>> "Redefining a class modifies the existing class object to reflect
>>>> the new class definition"
>>>
>>>
>>> You seem to suggest that...
>>>
>>> (defclass xyz ()
>>> ())
>>>
>>> ...should expand into...
>>>
>>> (ensure-class 'xyz
>>> :direct-superclasses nil
>>> :direct-slots nil
>>> :default-initargs nil
>>> :documentation nil
>>> :metaclass (find-class 'standard-class))
>>>
>>> However, what should the following expand to?
>>>
>>> (defclass xyz ()
>>> ()
>>> (:metaclass my-class-that-has-options-with-non-nil-default-values))
>>
>>
>> The same as this:
>>
>> (defclass xyz ()
>> ()
>> (:default-initargs)
>> (:metaclass my-class-that-has-options-with-non-nil-default-values))
>>
>> I gotta say, I am having a hard time even understanding this line of
>> argument you are trying to develop. Classes of your imagined metaclass
>> get metaclass-supplied default-initargs from....where? Perhaps you
>> could expand your counterexample to include the metaclass and the
>> magic default initargs.
>
>
> OK, maybe I haven't been clear enough. The :default-initargs option is
> an option understood by instances of standard-class. Other metaclasses
> may not accept this option (say, built-in-class) and, that's more
> important, again other metaclasses may want additional options. So for
> example, the metaclass my-metaclass may want to define a class option
> my-option, so that the programmer can say this:
>
> (defclass xyz ()
> ()
> (:my-option 'bla)
> (:metaclass my-metaclass))
>
> However, if programmers say this:
>
> (defclass xyz ()
> (:metaclass my-metaclass))
>
> ...they may want to have this by default be expanded to that:
>
> (ensure-class 'xyz
> ...
> :my-option ... some non-nil form ...)
> :metaclass my-metaclass)
It is unfortunate that your example jumps from defclass to ensure-class,
which is precisely the mistake AllegroCL and at least one other
implementation I do not recall makes. ensure-class is used to implement
defclass. ensure-class is not defclass. The spec for ensure-class is not
the spec for defclass. The MOP makes it possible to alter CLOS in
wondrous ways, but it does not say a metaclass implementation should
insert defclass options or labor to make defclass and ensure-class
behave the same.
The crux of the matter is these two being treated differently:
(defclass xyz ()
()
(:metaclass my-class-that-has-options-with-non-nil-default-values))
(defclass xyz ()
()
(:default-initargs)
(:metaclass my-class-that-has-options-with-non-nil-default-values))
Which is blatantly nuts unless one thinks defclass is ensure-class.
It is also unfortunate that you jumped from the :default-initargs option
to this new :my-option option to defclass, as if a metaclass wanting a
non-nil default for :my-option somehow affects the semantics of
:default-initargs. Not even the spec for ensure-class says "all options
to ensure-class must be treated the same", which, btw, would be quite a
bizarre kind of consistency to specify. the doc on that treats each
option differently (of course). The section "Initialization of Class
Metaobjects" begins:
"/Unless there is a specific note to the contrary/, then during
reinitialization, if an initialization argument is not supplied, the
previously stored value is left unchanged."
...and then discusses four or five options in detail. So not even at the
irrelevant level of ensure-class would the handling of
:direct-default-initargs (again note that we are at a whole different
level of OO implementation) have to be constrained by flexibility
desired for some new :my-option option to defclass.
So I see two huge problems: thinking ensure-class is defclass, and the
idea that for some possible extension option to be allowed a non-nil
default, a known option known to have nil as a default must be treated
as if it might not have nil as a default.
kt
Kenny Tilton wrote:
> It is unfortunate that your example jumps from defclass to ensure-class,
> which is precisely the mistake AllegroCL and at least one other
> implementation I do not recall makes. ensure-class is used to implement
> defclass. ensure-class is not defclass. The spec for ensure-class is not
> the spec for defclass. The MOP makes it possible to alter CLOS in
> wondrous ways, but it does not say a metaclass implementation should
> insert defclass options or labor to make defclass and ensure-class
> behave the same.
>
> The crux of the matter is these two being treated differently:
>
> (defclass xyz ()
> ()
> (:metaclass my-class-that-has-options-with-non-nil-default-values))
>
> (defclass xyz ()
> ()
> (:default-initargs)
> (:metaclass my-class-that-has-options-with-non-nil-default-values))
>
> Which is blatantly nuts unless one thinks defclass is ensure-class.
OK, maybe I should state that you are right, in the senses that it would
be better if both
(defclass xyz () ())
and
(defclass xyz () () (:default-inintargs))
would expand into
(ensure-class 'xyz ... :default-initargs nil)
So assume that I agree on this issue. I am only trying to find a
reasonable way to make this work.
The ad-hoc solution would be that the defclass macro knows about
:default-initargs. Letting ensure-class-using-class use a default of nil
for :default-initargs is not an option because we want (ensure-class
'xyz) not to change the default initargs for an existing class.
However, I'd be unhappy about such a solution because it means that the
CLOS implementor has more opportunities to define exceptional cases than
I would have when I implement my own metaclasses.
So the fundamental question I am asking is this: How can the defclass
macro learn about metaclass options and their default values in order to
make the desired behavior work even in the general (non-ad-hoc) case?
This is not a rhetorical question that is meant as an argument against
your position, but a "real" question that I think should (and can) be
answered.
> It is also unfortunate that you jumped from the :default-initargs option
> to this new :my-option option to defclass, as if a metaclass wanting a
> non-nil default for :my-option somehow affects the semantics of
> :default-initargs. Not even the spec for ensure-class says "all options
> to ensure-class must be treated the same", which, btw, would be quite a
> bizarre kind of consistency to specify. the doc on that treats each
> option differently (of course).
Yes, but it's possible to implement these specific differences in a
method on standard-class for ensure-class-using-class. That's not an
option for the desired defaulting for :default-initargs during
reinitialization (see above).
Pascal
--
Pascal Costanza University of Bonn
···············@web.de Institute of Computer Science III
http://www.pascalcostanza.de R�merstr. 164, D-53117 Bonn (Germany)
Pascal Costanza wrote:
> So the fundamental question I am asking is this: How can the defclass
> macro learn about metaclass options and their default values in order to
> make the desired behavior work even in the general (non-ad-hoc) case?
Another note: It should be possible to implement the ad-hoc solution now
and later on add a more general mechanism to the MOP spec later on.
Pascal
--
Pascal Costanza University of Bonn
···············@web.de Institute of Computer Science III
http://www.pascalcostanza.de R�merstr. 164, D-53117 Bonn (Germany)
From: Bruno Haible
Subject: Re: why does the mop handle default-initargs as persistent,
Date:
Message-ID: <chsjkf$olj$1@laposte.ilog.fr>
Pascal Costanza wrote:
>
> How can the defclass
> macro learn about metaclass options and their default values in order to
> make the desired behavior work even in the general (non-ad-hoc) case?
You are right; there should be a protocol that specifies this. It
could be a new GF that takes a class or generic-function as argument.
Or you could use the metaclass' default-initargs for this purpose.
Bruno
Bruno Haible wrote:
> Pascal Costanza wrote:
>
>>How can the defclass
>>macro learn about metaclass options and their default values in order to
>>make the desired behavior work even in the general (non-ad-hoc) case?
>
> You are right; there should be a protocol that specifies this. It
> could be a new GF that takes a class or generic-function as argument.
> Or you could use the metaclass' default-initargs for this purpose.
Yes, that would be a good idea because it would make things a little bit
more convenient.
However, wouldn't this require the defclass macro to already know about
the class metaobject if it already exists? There doesn't seem to be
enough opportunities in the MOP to add that without changing things
fundamentally, AFAICS. As yet, it's ensure-class's job to check whether
the metaobject already exists, but then you are already in the
functional layer where you want to keep things unchanged when they are
not explicitly passed.
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Bruno Haible
Subject: Re: why does the mop handle default-initargs as persistent,
Date:
Message-ID: <ci47mu$bmm$2@laposte.ilog.fr>
Pascal Costanza <········@web.de> wrote:
>>> How can the defclass
>>> macro learn about metaclass options and their default values in order to
>>> make the desired behavior work even in the general (non-ad-hoc) case?
>>
>> ... Or you could use the metaclass' default-initargs for this purpose.
>
> Yes, that would be a good idea because it would make things a little bit
> more convenient.
This is now implemented in GNU clisp.
> However, wouldn't this require the defclass macro to already know about
> the class metaobject if it already exists?
No, the defclass macro needs only to know about the class' metaclass
in order to use its default-initargs.
Bruno
Bruno Haible wrote:
> Pascal Costanza <········@web.de> wrote:
>
>>>>How can the defclass
>>>>macro learn about metaclass options and their default values in order to
>>>>make the desired behavior work even in the general (non-ad-hoc) case?
>>>
>>>... Or you could use the metaclass' default-initargs for this purpose.
>>
>>Yes, that would be a good idea because it would make things a little bit
>>more convenient.
>
> This is now implemented in GNU clisp.
>
>>However, wouldn't this require the defclass macro to already know about
>>the class metaobject if it already exists?
>
> No, the defclass macro needs only to know about the class' metaclass
> in order to use its default-initargs.
Ah, of course, you're right, and it's much simpler than my proposal.
Pascal
--
Pascal Costanza University of Bonn
···············@web.de Institute of Computer Science III
http://www.pascalcostanza.de R�merstr. 164, D-53117 Bonn (Germany)
Pascal Costanza wrote:
> So the fundamental question I am asking is this: How can the defclass
> macro learn about metaclass options and their default values in order to
> make the desired behavior work even in the general (non-ad-hoc) case?
>
> This is not a rhetorical question that is meant as an argument against
> your position, but a "real" question that I think should (and can) be
> answered.
Here is a first attempt (not tested):
(defmacro defclass (class-name superclasses slot-descriptions
&rest class-options
&environment env)
(let ((metaclass (let* ((cons (assoc :metaclass class-options))
(mc (if cons (cdr cons) 'standard-class)))
(find-class mc t env))))
`(ensure-class ',class-name
,@(ensure-class-user-args
(class-prototype metaclass)
superclasses slot-descriptions class-options)
:environment env))) ; <- does this work?
;; called ensure-class-user-args because they are the args
;; for the user interface macro
(defgeneric ensure-class-user-args
(class superclasses slot-descriptions class-options)
(:method ((class standard-class)
superclasses slot-descriptions class-options)
(list :direct-superclasses
(mapcar #'find-class superclasses)
:direct-slots
(canonicalize-slots slot-descriptions) ; or some such
:direct-default-initargs
(let ((cons (assoc :default-initargs class-options)))
(if cons (cdr cons) nil))
:documentation
(let ((cons (assoc :documentation class-options)))
(if cons (cdr cons) nil)))))
;; now it's possible to say this
(defmethod ensure-class-user-args
((class my-class)
superclasses slot-descriptions class-options)
(list* :my-option
(let ((cons (assoc :my-option class-options)))
(if cons (cdr cons) ... some non-nil form ...))
(call-next-method)))
;; something similar could probably be done for defgeneric /
ensure-generic-function...
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
Pascal Costanza wrote:
>
> Pascal Costanza wrote:
>
>> So the fundamental question I am asking is this: How can the defclass
>> macro learn about metaclass options and their default values in order
>> to make the desired behavior work even in the general (non-ad-hoc) case?
>>
>> This is not a rhetorical question that is meant as an argument against
>> your position, but a "real" question that I think should (and can) be
>> answered.
>
>
> Here is a first attempt (not tested):
>
> (defmacro defclass (class-name superclasses slot-descriptions
> &rest class-options
> &environment env)
> (let ((metaclass (let* ((cons (assoc :metaclass class-options))
> (mc (if cons (cdr cons) 'standard-class)))
> (find-class mc t env))))
> `(ensure-class ',class-name
> ,@(ensure-class-user-args
> (class-prototype metaclass)
> superclasses slot-descriptions class-options)
> :environment env))) ; <- does this work?
Damn, that just leaves me as the only Lispnik not writing their own
Lisp. :) The spec says:
"The options to defclass can be extended. It is required that all
implementations signal an error if they observe a class option or a slot
option that is not implemented locally."
So you'll have to write your own Lisp (not just a metaclass) if you want
to make defclass user-extensible.
kt
Kenny Tilton wrote:
> Pascal Costanza wrote:
>
>> Pascal Costanza wrote:
>>
>>> So the fundamental question I am asking is this: How can the defclass
>>> macro learn about metaclass options and their default values in order
>>> to make the desired behavior work even in the general (non-ad-hoc) case?
>>>
>>> This is not a rhetorical question that is meant as an argument
>>> against your position, but a "real" question that I think should (and
>>> can) be answered.
>>
>> Here is a first attempt (not tested):
>>
>> (defmacro defclass (class-name superclasses slot-descriptions
>> &rest class-options
>> &environment env)
>> (let ((metaclass (let* ((cons (assoc :metaclass class-options))
>> (mc (if cons (cdr cons) 'standard-class)))
>> (find-class mc t env))))
>> `(ensure-class ',class-name
>> ,@(ensure-class-user-args
>> (class-prototype metaclass)
>> superclasses slot-descriptions class-options)
>> :environment env))) ; <- does this work?
>
>
> Damn, that just leaves me as the only Lispnik not writing their own
> Lisp. :) The spec says:
>
> "The options to defclass can be extended. It is required that all
> implementations signal an error if they observe a class option or a slot
> option that is not implemented locally."
>
> So you'll have to write your own Lisp (not just a metaclass) if you want
> to make defclass user-extensible.
I don't understand this at all. What is your point here?
A metaclass definition looks like this:
(defclass my-class (standard-class)
((option :accessor my-option :initarg :my-option)))
Now I can say this:
(defclass my-object ()
(...)
(:metaclass my-class)
(:my-option ...))
I can't say that:
(defclass my-object ()
(...)
(:metaclass my-class)
(:foo ...))
...because :foo is not in the set of accepted initargs for my-class.
This check is already specified in detail in Section 7.1.2 of ANSI CL.
So I don't see any violation of the passage you cited from the spec.
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
Pascal Costanza wrote:
>
> Kenny Tilton wrote:
>
>> Pascal Costanza wrote:
>>
>>> Pascal Costanza wrote:
>>>
>>>> So the fundamental question I am asking is this: How can the
>>>> defclass macro learn about metaclass options and their default
>>>> values in order to make the desired behavior work even in the
>>>> general (non-ad-hoc) case?
>>>>
>>>> This is not a rhetorical question that is meant as an argument
>>>> against your position, but a "real" question that I think should
>>>> (and can) be answered.
>>>
>>>
>>> Here is a first attempt (not tested):
>>>
>>> (defmacro defclass (class-name superclasses slot-descriptions
>>> &rest class-options
>>> &environment env)
>>> (let ((metaclass (let* ((cons (assoc :metaclass class-options))
>>> (mc (if cons (cdr cons) 'standard-class)))
>>> (find-class mc t env))))
>>> `(ensure-class ',class-name
>>> ,@(ensure-class-user-args
>>> (class-prototype metaclass)
>>> superclasses slot-descriptions class-options)
>>> :environment env))) ; <- does this work?
>>
>>
>>
>> Damn, that just leaves me as the only Lispnik not writing their own
>> Lisp. :) The spec says:
>>
>> "The options to defclass can be extended. It is required that all
>> implementations signal an error if they observe a class option or a
>> slot option that is not implemented locally."
>>
>> So you'll have to write your own Lisp (not just a metaclass) if you
>> want to make defclass user-extensible.
>
>
> I don't understand this at all. What is your point here?
>
> A metaclass definition looks like this:
>
> (defclass my-class (standard-class)
> ((option :accessor my-option :initarg :my-option)))
>
> Now I can say this:
>
> (defclass my-object ()
> (...)
> (:metaclass my-class)
> (:my-option ...))
>
> I can't say that:
>
> (defclass my-object ()
> (...)
> (:metaclass my-class)
> (:foo ...))
My bad. I thought that might be the case, but only got as far as CLHS
7.7.25, which I must have misunderstood. But then why does defclass need
to "know about a metaclass's options"? These work:
(defclass my-class (standard-class)
((option :accessor my-option :initarg :my-option))
(:default-initargs
:my-option 'initarg-42))
(defclass my-class (standard-class)
((option :accessor my-option :initarg :my-option :initform 42)))
And AllegroCL is consistent in leaving options unchanged if unspecified
in a re-evaluation.
Come to think of it, this is like /slot/ initform values being ignored
on re-evaluations where the slot is class-allocated. I eventually
reconciled myself to that discordance between defclass form and the
behavior of make-instance by meditating on the metaclass instance which
represented the class, and thinking of the initform to the
class-allocated slot as something applied only at make-instance time (of
the metaclasss instance representing the class). So subsequent
evaluations of the defclass form, which are as the spec says modifying
the class object vs making a new one, would not involve consulting the
initform value of any class-allocated slot.
But now we have unearthed "...modifies the class object to reflect its
new definition". So changing the initform of a class-allocated slot....
uh-oh. Better get back to Cello. :)
kenny
--
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Kenny Tilton wrote:
> uh-oh. Better get back to Cello. :)
Yeah, this will get you 25 years until you have to fix similar problems. ;)
But by then you will have probably left the Lisp community, and instead
promote Observer-Oriented Programming for the then-fashionable successor
of AJ#. ;)
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
Kenny Tilton <·······@nyc.rr.com> wrote in message news:<·························@twister.nyc.rr.com>...
>
> Come to think of it, this is like /slot/ initform values being ignored
> on re-evaluations where the slot is class-allocated. I eventually
> reconciled myself to that discordance between defclass form and the
> behavior of make-instance by meditating on the metaclass instance which
> represented the class, and thinking of the initform to the
> class-allocated slot as something applied only at make-instance time (of
> the metaclasss instance representing the class). So subsequent
> evaluations of the defclass form, which are as the spec says modifying
> the class object vs making a new one, would not involve consulting the
> initform value of any class-allocated slot.
>
is that not just as much of a bug. if one changes the definition
to/from instance allocation, lisps manage to keep that straight.
...
james anderson wrote:
> Kenny Tilton <·······@nyc.rr.com> wrote in message news:<·························@twister.nyc.rr.com>...
>
>>Come to think of it, this is like /slot/ initform values being ignored
>>on re-evaluations where the slot is class-allocated. I eventually
>>reconciled myself to that discordance between defclass form and the
>>behavior of make-instance by meditating on the metaclass instance which
>>represented the class, and thinking of the initform to the
>>class-allocated slot as something applied only at make-instance time (of
>>the metaclasss instance representing the class). So subsequent
>>evaluations of the defclass form, which are as the spec says modifying
>>the class object vs making a new one, would not involve consulting the
>>initform value of any class-allocated slot.
>>
>
>
> is that not just as much of a bug.
It is a feature. <g> CLHS 4.3.6 documents it:
"The value of a slot that is specified as shared both in the old class
and in the new class is retained. If such a shared slot was unbound in
the old class, it is unbound in the new class. Slots that were local in
the old class and that are shared in the new class are initialized.
Newly added shared slots are initialized."
That seems to explicitly mandate as well:
> if one changes the definition
> to/from instance allocation, lisps manage to keep that straight.
kt
--
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Pascal Costanza <········@web.de> wrote in message news:<············@newsreader2.netcologne.de>...
> Bruno Haible wrote:
>
> > For the macros DEFCLASS, DEFGENERIC, however, a programmer expects
> > that executing the new definition erases the old definition; this is
> > also what ANSI CL 4.3.6 says:
> >
> > "Redefining a class modifies the existing class object to reflect
> > the new class definition"
>
> You seem to suggest that...
>
> (defclass xyz ()
> ())
>
> ...should expand into...
>
> (ensure-class 'xyz
> :direct-superclasses nil
> :direct-slots nil
> :default-initargs nil
> :documentation nil
> :metaclass (find-class 'standard-class))
>
> However, what should the following expand to?
>
> (defclass xyz ()
> ()
> (:metaclass my-class-that-has-options-with-non-nil-default-values))
>
>
> Pascal
would not ensure-class-using-class be sufficient to contend with that
case.
if one is implementing a new metaclass, one has the latitude to extend
the meta-behaviour of that class. one does not have that option with
standard-class.
...
james anderson wrote:
> would not ensure-class-using-class be sufficient to contend with that
> case.
Not if the metaclass programmer wants the defclass macro and
ensure-class to behave differently in a similar way as people would like
them to for :default-initargs.
Pascal
--
Pascal Costanza University of Bonn
···············@web.de Institute of Computer Science III
http://www.pascalcostanza.de R�merstr. 164, D-53117 Bonn (Germany)