Evaluate these in order...
(defclass diChange ()
((aaa :initarg :aaa :initform nil :reader aaa))
(:default-initargs :aaa 3))
(defclass diChange ()
((aaa :initarg :aaa :initform nil :reader aaa))
)
(aaa (make-instance 'diChange2))
...and you get "3".
I want nil! <g>
Jes curious....
ken
PS I'm using ACL for Windows NT, but I gather it's MOP I am up against.
PPS Onthe other hand...
(defclass diChange ()
((aaa :initarg :aaa :initform nil :reader aaa))
(:default-initargs))
(aaa (make-instance 'diChange2))
...and you get nil!!! I'm not buying this...<g>
Maybe I better reboot...evaluate in order:
(defclass diMadness ()
((aaa :initarg :aaa :initform nil :reader aaa))
(:default-initargs :aaa 3))
(defclass diMadness ()
((aaa :initarg :aaa :initform nil :reader aaa))
)
(aaa (make-instance 'diMadness))
;;;
;;; observe 3 (?!)
;;;
;;; strange enough, and then...
;;;
(defclass diMadness ()
((aaa :initarg :aaa :initform nil :reader aaa))
(:default-initargs))
(aaa (make-instance 'diMadness))
;;; observe nil
Ken
I guess the thing that gets me is that specifying :default-initargs with
no actual initargs serves to "clear" the original ":aaa 3", but /not/
specifying :d-i at all does not!
In neither case is the initarg :aaa specified, but the outcome is
different.
Were the implementers trying to give me a back door way of getting that
sucker out of there by straddling the issue? :)
I think I'll dust off my MCL and see what it says. (Not that that would
settle anything--unspecified is unspecified.)
Ken
The specification is silent on how class options are handled when
redefining a class (except that it only specifies the case where the
metaclass is STANDARD-CLASS both before and after). Your expectation,
which matches mine, is that the old class options should not be retained at
all in the updated class. But the above implementation seems to merge the
class options; if an option isn't mentioned in the new DEFCLASS form, it's
left the way it was.
The specification goes into great detail about how slots are updated during
a redefinition, but nothing about the situation you describe.
--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
...
>
> The specification is silent on how class options are handled when
> redefining a class (except that it only specifies the case where the
> metaclass is STANDARD-CLASS both before and after). Your expectation,
> which matches mine, is that the old class options should not be retained at
> all in the updated class. But the above implementation seems to merge the
> class options; if an option isn't mentioned in the new DEFCLASS form, it's
> left the way it was.
>
> The specification goes into great detail about how slots are updated during
> a redefinition, but nothing about the situation you describe.
>
One for X3J13.
Cheers
--
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
Barry Margolin wrote:
>
> metaclass is STANDARD-CLASS both before and after). Your expectation,
> which matches mine, is that the old class options should not be retained at
> all in the updated class. But the above implementation seems to merge the
> class options; if an option isn't mentioned in the new DEFCLASS form, it's
> left the way it was.
This expectation might seem to make sense when you first look at it,
but it's not a good thing. What if you want to retain the options? Then
you'll have to go through some MOP manipulations (and there might not be one).
You see in this case he knows exactly the value, so he can just specify
the :default-initargs he wants to ensure overridden.
I'm guessing that the logic is something like:
(when default-initargs-specified-p
(setf (class-default-initargs class) default-initargs))
If you specify
(:default-initargs)
then default-initargs-specified-p will be true, but default-initargs will
be the empty list.
Anyone executing DEFCLASS should be expected to know the full definition of
the class. You don't use this operation to make incremental adjustments to
an existing class.
Fernando Mato Mira wrote:
>
> Barry Margolin wrote:
>
Your expectation,
> > which matches mine, is that the old class options should not be retained at
> > all in the updated class.
....
> This expectation might seem to make sense when you first look at it,
> but it's not a good thing. What if you want to retain the options?
In what scenario do I change a class definition not to have any
:default-initarg clause yet want the prior clause to remain in effect?
The only one I can think of is that I am sitting at a teletype machine
interacting with Lisp and want to avoid the typing. (desperately hoping
this is /not/ the rationale. <g>)
Ken
um, it appears that you're suggesting that redefinitions are bad in
general, but I hope you restrict your discommendation to _partial_
definitions, not incremental ones. care to clarify?
#:Erik
You know, I am ultra-happy with ACL and the folks at Franz, but I think
I will press them on the fig leaf of the behavior not being specified.
If the behavior is plain wrong (I am still open for insights on how this
behavior could be right), absence of instruction does not make it right.
I'm not sure how you get that impression. My expectations is that when you
redefine a class, the class's definition should be as if that were the
original definition. The language has features for updating instances that
were created under the old definition, but new instances should not be
affected by that stuff.
Barry Margolin wrote:
> I'm not sure how you get that impression. My expectations is that when you
> redefine a class, the class's definition should be as if that were the
> original definition.
If you view the original definition as overriding some mythical null definition,
then the argument can be used to support the opposite view.
In this case, you're forgetting to take into account the dynamic nature of
Lisp. Nobody said the new defclass is being written by you at the prompt,
where you can see everything. It is conceivable for an OODBMS
to do a defclass to dynamically modify an schema. Of course, I don't
know how it would do to just add an slot w/o using the MOP and w/o
keeping additional state, so things are not so neat.
I could go with Franz modifying their implementation if there was
a REDEFINE-CLASS function that worked incrementally, but as things
are, I find their interpretation more useful. You should be careful about
not just reloading a file where you've elided an option, though.
Is there any other feature in Lisp where redefining something only replaces
the aspects that were explicitly mentioned in the new definition, leaving
other attributes as specified in the earlier definition? I don't think
so. So why would you expect DEFCLASS to do so? When I execute a DEFCLASS,
I'm saying "This is the definition of the class; forget about anything I
told you before."
> Is there any other feature in Lisp where redefining something only replaces
> the aspects that were explicitly mentioned in the new definition, leaving
> other attributes as specified in the earlier definition? I don't think
> so. So why would you expect DEFCLASS to do so? When I execute a DEFCLASS,
> I'm saying "This is the definition of the class; forget about anything I
> told you before."
I absolutely agree. This is the only rational/coherent definition
of "incremental (re)definition".
The thing where you have to use (:default-initargs) instead of
omitting that clause seems to me like an implementation bug.
Kent M Pitman wrote:
> Barry Margolin <bar...@bbnplanet.com> writes:
>
> > Is there any other feature in Lisp where redefining something only replaces
> > the aspects that were explicitly mentioned in the new definition, leaving
> > other attributes as specified in the earlier definition? I don't think
> > so. So why would you expect DEFCLASS to do so? When I execute a DEFCLASS,
> > I'm saying "This is the definition of the class; forget about anything I
> > told you before."
>
> I absolutely agree. This is the only rational/coherent definition
> of "incremental (re)definition".
total redefinition, yes. Incremental no. `redefinition', hmm.
I agree that defclass would be less schizophrenic if it did full redefinition,
but some non-MOP
facility is needed for `incremental definition adjustments', specially the `add
slot' and `change defaults' things.
> The thing where you have to use (:default-initargs) instead of
> omitting that clause seems to me like an implementation bug.
I don't know. But you should know if it was left out on purpose
to give leeway to the implementations.
But for sure some CLOS implementations are broken where
ANSI/AMOP say nothing. Specifically, when the DEFCLASS _macro_ does
more work than it needs to, preventing implementation of metaclass inheritance,
for example.
> I agree that defclass would be less schizophrenic if it did full
> redefinition, but some non-MOP facility is needed for `incremental
> definition adjustments', specially the `add slot' and `change
> defaults' things.
I believe this is what "functions" are for. I think "definitions" are
for declaration purposes and when you see them a second time you should
think "this is someone changing my axiom base and asking me to rethink
what I've previously known as if the original had not happened" rather
than "this is a second definition because i think it's normal to follow
a defun with a defun or a defclass with a defclass". unless you're
prepared to see multiple defclasses for the same object meaningfully
follow each other in a file (and by meaningfully, i don't just mean
entirely superseding the previous as a new arrives), i don't think
you should attach meaning which will lead someone to think they
should do this.
> > The thing where you have to use (:default-initargs) instead of
> > omitting that clause seems to me like an implementation bug.
>
> I don't know. But you should know if it was left out on purpose
> to give leeway to the implementations.
I have had plenty of practical experience with this issue because
Flavors had a facility that let you fudge around with these things
and it invariably made a mess when you reloaded things. I learned
not to use it even for purposes that were "intended".
> But for sure some CLOS implementations are broken where ANSI/AMOP
> say nothing. Specifically, when the DEFCLASS _macro_ does more work
> than it needs to, preventing implementation of metaclass
> inheritance, for example.
I'm not sure I understood this last point. Maybe you could give an
example? In any case, none of my statements about this being "right"
or "wrong" are assertions about conformance (for which I would use
the term "conforming" or "nonconforming" hopefully in most cases).
My statements about what is right is based in a belief about what is
appropriate to the language design, and about what should be the
definition. If you want to make a case that I'm "wrong" about that,
that's also fair--I just need to see an example because I have a weak
brain and I think better about concrete issues than abstract ones.
(The reason I so often can expound on abstracts here is that I have
very concrete experiences that inform those abstracts...)
> > so. So why would you expect DEFCLASS to do so? When I execute a DEFCLASS,
> > I'm saying "This is the definition of the class; forget about anything I
> > told you before."
>
> I absolutely agree. This is the only rational/coherent definition
> of "incremental (re)definition".
>
> The thing where you have to use (:default-initargs) instead of
> omitting that clause seems to me like an implementation bug.
Yes, that's the way I see it, too. But the implementation bug seems
to be "portable", in that CMU CL (whose CLOS is PCL-based) has the
same behaviour. So maybe someone did think this was in some way
useful behaviour, though I can't imagine why...
Regs, Pierre.
--
Pierre Mai <pm...@acm.org> http://home.pages.de/~trillian/
"One smaller motivation which, in part, stems from altruism is Microsoft-
bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
> Yes, that's the way I see it, too. But the implementation bug seems
> to be "portable", in that CMU CL (whose CLOS is PCL-based) has the
> same behaviour. So maybe someone did think this was in some way
> useful behaviour, though I can't imagine why...
A great many implementations were PCL-based to start with so share a common
set of accidents. Others may have tried to match on the hard cases.
And some bugs are easy to have happen if you're not thinking.
None of these should be confused with conscious thought.
If someone wants to advance an argument as to why experience and common
sense should not win out here, they're welcome to. But I will not by
default assume that behavior like this is a good idea.
Just my personal opinion.
> Is there any other feature in Lisp where redefining something only replaces
> the aspects that were explicitly mentioned in the new definition, leaving
> other attributes as specified in the earlier definition? I don't think
> so. So why would you expect DEFCLASS to do so? When I execute a DEFCLASS,
> I'm saying "This is the definition of the class; forget about anything I
> told you before."
DEFGENERIC comes to my mind, although the situtation is not quite the
same.
I think DEFGENERIC should also have removed those methods that were
defined by DEFMETHODs on the same function, not only those mentioned in
the DEFGENERIC form itself.
What, btw, is the recommended way of removing all old methods of
a generic function?
--
espen
I use FMAKUNBOUND on the symbol to get rid of everything.
#:Erik
Why? A DEFCLASS should only appear in one place: the class definition
source file. If you need to make incremental adjustments, use a text
editor and reload. Why should DEFCLASS be any different from any other
defining macro in the language? Nowhere else do we have incremental
adjustments, so why is it "needed" for this?
In fact, OO programming provides its own mechanism for incremental
adjustments: defining subclasses.
In fact, I believe DEFGENERIC's design is consistent with what I was
saying. Redoing a DEFGENERIC undoes what the old DEFGENERIC did and then
does what the new one says. The idea is to make things be as if you had
originally used the new DEFGENERIC. I.e.
DEFGENERIC-1
DEFMETHOD-1
DEFMETNOD-2
DEFGENERIC-2
has the same end result as
DEFGENERIC-2
DEFMETHOD-1
DEFMETHOD-2
Well, it's a bit heavyweight for getting rid of only "some" methods.
But mostly it's what I do most of the time, too, since I would usually
rather just reload the methods.
Sometimes I also delete-package. Heh... Does that make you feel
better about fmakunbound?
> Well, it's a bit heavyweight for getting rid of only "some" methods.
> But mostly it's what I do most of the time, too, since I would usually
> rather just reload the methods.
My problem domain is a set of two files, one of them contains some default
methods for a couple of generic functions, the other one contains user-
definable methods hidden in macros. These gf-s are three-place-
dispatching (yes!) and define a security policy. The user of this
system will expect rules he has deleted to disappear when he reloads
the file.
I guess I'll have to write a small function that does an fmakunbound
and then defines the default methods and reloads the configuration file.
> Sometimes I also delete-package. Heh... Does that make you feel
> better about fmakunbound?
You don't scare me ;-) I quite often do things like e.g.
(do-symbols (x :gazonk)(unintern x :gazonk))
--
espen
CL-USER 1 > (defclass diMadness ()
((aaa :initarg :aaa :initform nil :reader aaa))
(:default-initargs :aaa 3))
#<STANDARD-CLASS DIMADNESS 20FFFCB4>
CL-USER 2 > (aaa (make-instance 'diMadness))
3
CL-USER 3 > (defclass diMadness ()
((aaa :initarg :aaa :initform nil :reader aaa))
)
#<STANDARD-CLASS DIMADNESS 20FFFCB4>
CL-USER 4 > (aaa (make-instance 'diMadness))
NIL
Marcus.
Espen Vestre wrote:
>
> Kent M Pitman <pit...@world.std.com> writes:
>
> > Well, it's a bit heavyweight for getting rid of only "some" methods.
> > But mostly it's what I do most of the time, too, since I would usually
> > rather just reload the methods.
>
> I guess I'll have to write a small function that does an fmakunbound
> and then defines the default methods and reloads the configuration file.
>
What's all this about there being a problem eliminating individual
methods of a generic function? I do it all the time via interface tools
in both ACL and MCL (the latter a user contrib).
My guess is they use: (setf (generic-function-methods <gf>) (delete <m>
(g-f-m <gf>))
of course, if your environment has weak AMOP support...
kt
I just noticed the above comment in the original post. If you don't use
the MOP, you can't be "up against" it. The MOP allows users to create
their own metaclasses that have different behavior from "normal" CLOS, but
doesn't have any impact on the behavior of standard classes. ANSI CL
acknowledges the existence of metaclasses and the possibility of a MOP, but
doesn't describe it in any way; if you stick to using the CLOS operations
and metaclasses listed in the standard, you can safely forget that the MOP
exists.
The problem in this case, as I mentioned earlier, is that different
implementors have interpreted the lack of any specification of this aspect
of class redefinition differently.
that you don't know a priori which to remove.
| I do it all the time via interface tools in both ACL and MCL (the latter
| a user contrib).
that is not useful if you want to load a file.
| My guess is they use: (setf (generic-function-methods <gf>) (delete <m>
| (g-f-m <gf>)) of course, if your environment has weak AMOP support...
REMOVE-METHOD is the standard interface.
#:Erik
I believe we were constraining the answer to ANSI CL. The MOP is an
extension, not part of the standard.
[*** flame on ***]
I am simply aghast that no one could or would find the appropriate
places in the ANS and MOP that explain this behavior.
Shame on you all!
[*** flame off ***]
(Of course, I someone already posted this info and I missed, my
apologies for the outburst. :-)
KT submitted this issue to Franz customer support, and I was the one
who supplied them with an analysis which I believe he has received by
now. I'll repeat it below with some expanded comments.
I have to mention one underlying principle. There were various
remarks in this thread that one should limit consideration to the
ANS. Our implementation and various others make a different
choice and try to conform to the MOP, such as it is, as a de facto
standard. The MOP isn't perfect, nor is anyone's conformance to it,
but unless it is treated as a serious area of the language how can
anyone use it in the rare circumstances where it is appropriate?
And how can the community gather real-world experience in MOP usage?
Here is my analysis of the :default-initargs issue:
The AMOP specification in Chapter 6, pp. 193 ff., Initialization of
Class Metaobjects, states:
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.
Immediately below, on :direct-default-initargs :
If the class metaobject is being initialized, this argument defaults
to the empty list.
"initialized" here seems intentionally distinct from "reinitialized".
Note that the :default-initargs argument to defclass becomes
(by way of ensure-class) the :direct-default-initargs initialiation
argument and attribute when the class object is (re)initialized.
This is spelled out in Section 5.4.2 on the treatment of the defclass
macro.
Now, I believe that the thus AMOP specifies the behavior exhibited by
Allegro and various other implementations, although I suppose there
is room to debate my interpretation.
It is a completely different question, of course, whether the AMOP
made the right choice, or whether the defclass macro (distinct from
ensure-class and friends!) should be required to supply explicit nil
values for omitted option parameters. But IMO that question should
have been considered only after understanding the current behavior.
On the general subject of reexecuting standard cl def* forms, I've made
a little list of observations that I will post as a separate subthread.
I view the issue of redefinition as being somehow related to the
issue of retrieving definitions from the environment. X3J13
intended generally to address the various places in a language
where information once specified could not be retrieved by
standard operators. This motivated various new readers and
accessors such as the hashtable-mumble family and accessors
for new language entities like compiler-macro-function. But we
didn't address everything.
I spent only about five minutes annotsting the list below,
without much reference to the ANS itself, so it's probably
full of mistakes and omissions. The intention is to show the
variety of ways DEF* forms fail to be transparent, undoable,
and or redefinable.
defclass
some sticky options if not explicitly overridden.
defconstant
cannot undo special decl.
redefinition semantics explicitly undefined.
defgeneric
some sticky options if not explicitly overridden.
define-condition
as for defclass.
define-method-combination
cannot undo. Anything else? Who knows?
define-setf-expander
cannot undo.
define-symbol-macro
cannot undo.
cannot retrieve definition directly, but simple macroexpand
of the variable reveals everything.
defpackage
redefinition semantics undefined.
defparameter
cannot undo special decl.
defsetf
cannot undo.
defstruct
cannot undo.
old accessors are not removed.
deftype
cannot undo.
defvar
cannot undo special decl.
In addition, many of these operators are vague or silent about
documentation. Often the ANS specifies that a doc string
is associated with the frob if one is present, but there is no
explicit mention of removing a previous doc string if no doc
string is present in a redefinition.
> KT submitted this issue to Franz customer support, and I was the one
> who supplied them with an analysis which I believe he has received by
> now.
Yes, and I accepted that the behavior, however wrong it seemed to me,
was supported by AMOP, so I came here to ask, in effect, Am I missing
something? Who would want such a thing?
You see, long ago I was initially dumbfounded that changing the initform
on a class-allocated slot did change the slot's value during a session,
and then a light went on and I saw why that was correct.
I came here looking for the same enlightenment. My subject line was as
precise as it was goofy: could someone please justify to me what struck
me as a bit of MOP madness.
That said, I now feel differently about this. I do not think AMOP
supports this behavior:
>
> 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.
>
To me, that specifies class re-initialization, not 'defclass', not even
recompilation of a changed 'defclass'. If 'defclass :default-initargs
should not be sticky (somehow an open question <g>), the implementer of
'defclass' has to take the behavior of 'reinitialize-instance into
account.
Which brings me back to, How can this interpretation conceivably be
justified? And I was asking from the standpoint of language semantics,
not "well, AMOP does not say it is wrong".
Finally, I can easily imagine the author of a spec for #'+ going on for
pages and forgetting to say the result should be the arguments added up,
but still...<g>
Ken Tilton
Happy ACL User
Big Fan of Franz t/s
> That said, I now feel differently about this. I do not think AMOP
> supports this behavior:
>
> > 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.
>
> To me, that specifies class re-initialization, not 'defclass', not even
> recompilation of a changed 'defclass'. If 'defclass :default-initargs
> should not be sticky (somehow an open question <g>), the implementer of
> 'defclass' has to take the behavior of 'reinitialize-instance into
> account.
I'm willing later to discuss what you want to happen, but first
I insist we nail down what the ANS and AMOP define as the current,
required behavior. I find the behavior specified by the AMOP to be
almost perfectly explicit. I'll cite two passages again, more fully
than before:
From the treatment of the defclass macro, p.149, emphasis added:
The default initargs class option, IF IT IS PRESENT in the defclass
form, becomes the value of the :direct-default-initargs keyword
argument to ensure-class. [Continues to discuss canonicalization,
etc.]
From _Initialization of Class Metaobjects_, pp 193-4:
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.
...
The :direct-default-initargs argument ... If the class object is
being initialized, this argument defaults to the empty list.
Now, the crux of the matter is whether "initialized" in the last
quoted line is intended to cover both initialization time and
reinitialization time (your reading), or just initialization time
(my reading). I believe in the context of the immediately-preceding
line that my reading is correct, but comparison of the description
of the :name initialization argument clinches it, p.195:
The :name argument is an object. If the class is being initialized,
this argument defaults to nil.
This is essentially the same language. Do you really think that
a call to ensure-class to reinitialize a class metaobject should
reinitialize the name attribute of the class to nil if the name
was not explicitly included in the call? Feels pretty bogus to me.
So, can we establish agreement about what the MOP currently says?
Now on to your other question:
> Which brings me back to, How can this interpretation conceivably be
> justified? And I was asking from the standpoint of language semantics,
> not "well, AMOP does not say it is wrong".
I haven't yet thought deeply about whether this behavior would
or would not necessarily be a good thing, but the behavior of
ensure-class and friends -- _not_ defaulting missing arguments when
called for redefinition -- is the right thing. (Imagine a program
that frequently tweaks class definitions at run time -- the mop is
supposed to be able to support that.) I do agree that the behavior
of defclass, as a top-level defining form, is more surprising.
I suppose the least disruptive way to change the AMOP specification
would be require the defclass implementation to default and
explicitly include in the expansion some (or all? -- but think about
:metaclass!) of the omitted option clauses.
Here's the problem. The set of options to defclass is _not_ a
closed set. The ANS dictionary entry for defclass 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.
But the AMOP goes further and is quite more explicit, p.149:
Any other class options become the value of keyword arguments with
the same name. The value of the keyword argument is the tail of
the class option.
The ability of defclass to pass additional, unanticipated options
to ensure-class is fundamental if defclass is to be used with
specialized class metaclasses. But since the set of allowable init
keywords cannot be known to defclass at macroexpansion time, there
is no way defclass could be similarly courteous and supply a default
nil value for you.
My conclusion is that it would be possible to redefine the MOP
to specify that :default-initargs always defaults to nil in the
macroexpansion of defclass, and this doesn't even require changing
the ANS. But then your initial surprise that :default-initargs
don't disappear has just moved deeper, into more mysterious parts
of the system. Although :default-initargs has been fixed, the same
surprising behavior would occur for any specialized metaclass
initialization arguments.
Therefore I see an argument of consistency -- admittedly a rather
weak argument -- that :default-initargs should remain as it is and
work just like the infinite set of other potential defclass class
options.
> Ken Tilton
> Happy ACL User
> Big Fan of Franz t/s
Let me see if I can keep this thread going long enough to change that.
Just kidding...
Ok, but we are talking about what should happen when a 'defclass form
does not include :default-initargs, so...
> From the treatment of the defclass macro, p.149, emphasis added:
>
> The default initargs class option, IF IT IS PRESENT in the defclass
> form, becomes the value of the :direct-default-initargs keyword
> argument to ensure-class.
...doesn't help.
You then cite the very clear spec for the /class/ reinitialize-instance
internals /behind/ 'defclass, as if that spec also specified 'defclass
behavior, but they are two different things.
To me it is as if you were invoking specs for P5 assembler logical
operations to support 'logior behavior. Two different animals, though
one implements the other.
Put another way, who says 'defclass should expose the workings of
reinitialization of a class? That cannot be automatically so.
If someone wants to specify 'defclass as working that way, that is
another matter, but no one has.
> From _Initialization of Class Metaobjects_, pp 193-4:
>
> 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.
> ...
> The :direct-default-initargs argument ... If the class object is
> being initialized, this argument defaults to the empty list.
>
That's about MOP internals, not 'defclass, explicitly or implicitly.
> Now, the crux of the matter is whether "initialized" in the last
> quoted line is intended to cover both initialization time and
> reinitialization time (your reading)
No! I agree with your reading as it applies to MOP internals. If I were
implementing 'defclass I would take that to heart and see to it that,
were :d-i not specified, I explicitly passed nil to
reinitialize-instance on the class instance.
> So, can we establish agreement about what the MOP currently says?
<g>
> (Imagine a program
> that frequently tweaks class definitions at run time -- the mop is
> supposed to be able to support that.)
Yeah, but via 'defclass?? Nah, I'll use MOP internals. besides, a
program has no excuse for being lazy about "retyping".
> The ability of defclass to pass additional, unanticipated options
> to ensure-class is fundamental if defclass is to be used with
> specialized class metaclasses. But since the set of allowable init
> keywords cannot be known to defclass at macroexpansion time, there
> is no way defclass could be similarly courteous and supply a default
> nil value for you.
This is more promising! Except if I create a metaclass, do I not also
create methods that get a crack at the new options I have in mind? So
the 'standard-class implementation does not have to worry about handling
those courteously--that is the metaclass implementers problem.
So I do not see this as a consistency thing: :default-initargs is the
standard-class's baby, and can do the Right Thing here regardless of how
metaclass implementers handle their options.
> > Ken Tilton
> > Happy ACL User
> > Big Fan of Franz t/s
>
> Let me see if I can keep this thread going long enough to change that.
>
> Just kidding...
Sheesh, so much for the customer always being right! <g>
Well, I think we can keep this going on a long time because you are
looking to the texts for support and I am focused on how weird the
outcome is!
Does it matter what AMOP says about (what I claim are) MOP internals?
I am a 'defclass user, not a 'defclass implementer. Let me point out
again that after:
(defclass xxx ((aaa :initform :aaa))()(:default-initargs :aaa 3))
these two forms yield different results (in ACL!):
(defclass xxx ((aaa :initform :aaa))()(:default-initargs))
versus:
(defclass xxx ((aaa :initform :aaa))())
ACL's behavior effectively exposes 'ensure-class behavior. 'defclass is
not documented as having sticky initargs, and I think it would have to
be for ACL to be correct, since this is so counterintuitive.
And--not to invoke mob rule--but is there another Lisp that does this?
Ken
Still happy
Still fan
> Put another way, who says 'defclass should expose the workings of
> reinitialization of a class? That cannot be automatically so.
Well put. The semantics of an operator implemented by a certain technique
cannot automatically inherit the underlying protocol conventions. To say
it could suggests there cannot be an implementation using a different
underlying protocol with different conventions. There is no substitute
for conscious design at every level.
> [...]
> That's about MOP internals, not 'defclass, explicitly or implicitly.
Especially since the MOP is not required to be the underlying
implementation of CLOS.
The behavior described is, as I mentioned, a permissible implementation.
And Steve's defense of it seems a legitimate one. But I prefer to
think design will precede implementation, not follow from it, and
I think this is bad design which should be fixed by not even using
instances to carry around this instance, if that's what it takes to make
the implementation not have to violate its own MOP theory.
Further, there is nothing in the MOP itself which requires the instance
not to receive an init keyword just becuase an init keyword didn't occur
in the surface syntax of the defclass.
> > Now, the crux of the matter is whether "initialized" in the last
> > quoted line is intended to cover both initialization time and
> > reinitialization time (your reading)
>
> No! I agree with your reading as it applies to MOP internals. If I were
> implementing 'defclass I would take that to heart and see to it that,
> were :d-i not specified, I explicitly passed nil to
> reinitialize-instance on the class instance.
Again, I agree. I was going to write this same message myself and I'm
so glad you saved me the trouble.
- - - - -
Incidentally, I'm of mixed minds sometimes but generally I'm down on use
of supplied-p variables. They make it a pain in the neck when trying to
do pass-through composition where someone picks up some arguments, adds
or changes a value, and then tries to put it all back together. You
have to use a lot of
,@(if foo-p `(:foo ,foo))
where you wish you could write just
:foo ,foo
And while this is not a supplied-p problem, it's similar. I do use
supplied-p sometimes, mind you, but always mindful of the fact that
I'm working with stuff I'll probably regret later, or someone else will.
I think it's fine for Franz to take the position they have, but they
should know they do it expecting outrage because this is a highly predictable
situation of controversy. And while my maxim is "there are no controversial
answers, only controversial questions", I do think that some controversial
questions have answers that are more popular than others. And this is one.
> Fernando Mato Mira <mato...@iname.com> writes:
>
> > I agree that defclass would be less schizophrenic if it did full
> > redefinition, but some non-MOP facility is needed for `incremental
> > definition adjustments', specially the `add slot' and `change
> > defaults' things.
>
> I believe this is what "functions" are for. I think "definitions" are
> for declaration purposes and when you see them a second time you should
I agree with this, but more because DEFCLASS is an `eval thing' (for
typists), while ENSURE-CLASS is an `apply thing' (for programs).
> > But for sure some CLOS implementations are broken where ANSI/AMOP
> > say nothing. Specifically, when the DEFCLASS _macro_ does more work
> > than it needs to, preventing implementation of metaclass
> > inheritance, for example.
>
> I'm not sure I understood this last point. Maybe you could give an
> example? In any case, none of my statements about this being "right"
I had to modify the PCL in CMUCL, and I had to get patches
for Harlequin and ACL, too to be able to implement the metaclass inheritance
facility in ECLOS. See "Why the MOP should be mopped" in
http://ligwww.epfl.ch/matomira/en/publications.html
Regarding this case, defaulting of initialization keywords should be
the responsibility of methods specialized in the appropriate metaclass,
not of DEFCLASS. That's why the DEFCLASS specification cannot
say nothing in general about them, only about STANDARD-CLASS and
STRUCTURE-CLASS.
[SNIP]
> I am a 'defclass user, not a 'defclass implementer. Let me point out
> again that after:
>
> (defclass xxx ((aaa :initform :aaa))()(:default-initargs :aaa 3))
>
> these two forms yield different results (in ACL!):
>
> (defclass xxx ((aaa :initform :aaa))()(:default-initargs))
>
> versus:
>
> (defclass xxx ((aaa :initform :aaa))())
>
> ACL's behavior effectively exposes 'ensure-class behavior. 'defclass is
> not documented as having sticky initargs, and I think it would have to
> be for ACL to be correct, since this is so counterintuitive.
>
> And--not to invoke mob rule--but is there another Lisp that does this?
Did a small test using CMU CL (I just installed it, why not try it
out, neh?) and it seems to behave the way you didn't expect it to. Me,
I haven't fooled around with CLOS enough to feel either way.
And I had to modify the class definition slightly, to make either
Allegro or CMU happy about it, something about bad class/class name.
Both runs are from a freshly started lisp image, to minimize
cross-pollution.
[Lisp]
CMU Common Lisp 18b, running on head.ingvar.home
Send questions to cmucl...@cons.org. and bug reports to cmuc...@cons.org.
Loaded subsystems:
Python 1.0, target Intel x86
CLOS based on PCL version: September 16 92 PCL (f)
[case #1]
* (defclass xxx () ((aaa :initarg :aaa))(:default-initargs :aaa 3))
#<STANDARD-CLASS XXX {9022665}>
* (setq foo (make-instance 'xxx))
Warning: Declaring FOO special.
#<XXX {9025F2D}>
* (slot-value foo 'aaa)
3
* (defclass xxx () ((aaa :initarg :aaa))(:default-initargs)) ;
#<STANDARD-CLASS XXX {9022665}>
* (setf bar (make-instance 'xxx))
Warning: Declaring BAR special.
#<XXX {9032635}>
* (slot-value bar 'aaa)
The slot AAA is unbound in the object #<XXX {9032635}>
[Enter debugger]
[Case #2]
* (defclass xxx () ((aaa :initarg :aaa))(:default-initargs :aaa 3))
#<STANDARD-CLASS XXX {902232D}>
* (setf foo (make-instance 'xxx))
Warning: Declaring FOO special.
#<XXX {9025C2D}>
* (slot-value foo 'aaa)
3
* (defclass xxx () ((aaa :initarg :aaa)))
#<STANDARD-CLASS XXX {902232D}>
* (setf bar (make-instance 'xxx))
Warning: Declaring BAR special.
#<XXX {9032165}>
* (slot-value bar 'aaa)
3
* (quit)
//Ingvar (anyone interested in a CL nntp reading package? Guessed not)
Thx for checking out another Lisp. So far it's 2-2. :)
>
> And I had to modify the class definition slightly, to make either
> Allegro or CMU happy about it, something about bad class/class name.
Oops. yeah, i was just typing off the top of my head.
Ken