From: james anderson
Subject: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <26019fbd.0409072313.2411cf61@posting.google.com>
rather than treating them like metaobject or
argument-precedence-order? could someone who was party to the
deliberations shed some light on this?

thanks,
...

From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chmcpo$6e0$1@newsreader2.netcologne.de>
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."
From: Kenny Tilton
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <nGX%c.6276$as.2306688@twister.nyc.rr.com>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chplbd$12k4$1@f1node01.rhrz.uni-bonn.de>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chq042$acs$1@newsreader2.netcologne.de>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chqbu2$9g$1@newsreader2.netcologne.de>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chq0b0$afv$1@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

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Kenny Tilton
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <k450d.33042$Ot3.31771@twister.nyc.rr.com>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chrr8e$fvl$1@newsreader2.netcologne.de>
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."
From: Kenny Tilton
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <OHg0d.114055$4h7.17984694@twister.nyc.rr.com>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chs8gs$guo$1@f1node01.rhrz.uni-bonn.de>
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)
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chs92e$guo$3@f1node01.rhrz.uni-bonn.de>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chsohd$664$1@newsreader2.netcologne.de>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <ci4908$12hu$1@f1node01.rhrz.uni-bonn.de>
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)
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chso94$5pg$1@newsreader2.netcologne.de>
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."
From: Kenny Tilton
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <Mom0d.33536$Ot3.23224@twister.nyc.rr.com>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chuj7r$8ah$1@newsreader2.netcologne.de>
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."
From: Kenny Tilton
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <GDD0d.115600$4h7.18436741@twister.nyc.rr.com>
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
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chv2h0$38e$1@newsreader2.netcologne.de>
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."
From: james anderson
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <26019fbd.0409130416.4f6a34a0@posting.google.com>
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.

...
From: Kenny Tilton
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <Rhj1d.117793$4h7.19315067@twister.nyc.rr.com>
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
From: james anderson
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <26019fbd.0409100417.340d5366@posting.google.com>
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.

...
From: Pascal Costanza
Subject: Re: why does the mop handle default-initargs as persistent,
Date: 
Message-ID: <chs8lr$guo$2@f1node01.rhrz.uni-bonn.de>
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)