> 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.
> > 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...
In article <37375758.AF367...@liii.com>, Kenny Tilton <t...@liii.com> wrote:
>PS I'm using ACL for Windows NT, but I gather it's MOP I am up against.
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.
-- 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.
In article <3739BD3C.97CE5...@liii.com>, Kenny Tilton <t...@liii.com> wrote:
>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...
I believe we were constraining the answer to ANSI CL. The MOP is an extension, not part of the standard.
-- 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.
I'm replying to the initial message of this thread. Someone clued me into the fact that it had appeared, and I just read through the whole thing.
[*** 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.
Here is my promised list of redefinition issues with standard CL DEF* forms.
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>
Kenny Tilton wrote: > 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.
> but first > I insist we nail down what the ANS and AMOP define as the current, > required behavior.
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:
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?
Kenny Tilton <t...@liii.com> writes: > 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.
Kent M Pitman wrote: > Fernando Mato Mira <matom...@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
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.
> 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-h...@cons.org. and bug reports to cmucl-...@cons.org. Loaded subsystems: Python 1.0, target Intel x86 CLOS based on PCL version: September 16 92 PCL (f)
> 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.
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.