Hi,
In the CLHS page for ENSURE-GENERIC-FUNCTION, there is this paragraph:
"If function-name specifies a generic function that has a different value for the :generic-function-class argument and if the new generic function class is compatible[1] with the old, change-class is called to change the class of the generic function; otherwise an error is signaled."
In the AMOP however, one can read the following.
From the page on ENSURE-GENERIC-FUNCTION:
"The behavior of this function is actually implemented by the generic function ensure-generic-function-using-class. When ensure-generic-function is called, it immediately calls ensure-generic-function-using-class and returns that result as its own."
And then from the page on ENSURE-GENERIC-FUNCTION-USING-CLASS: "If the class of the generic-function-or-nil argument is not the same as the class specified by the :generic-function-class argument, an error is signaled."
Let alone the fact that this should only apply when there actually is an existing generic function, this seems to be in contradiction with the Common Lisp standard, as it would explicitly forbid changing the class of the generic function, even in a "compatible" way.
Comments?
Footnotes: [1] BTW, what does "compatible" mean ?
Hi,
First of all, apologies for missing the discrepancy you’re pointing out in my previous posting about this topic.
Secondly, the general rule is: If there is a discrepancy between ANSI CL and AMOP, and ANSI CL has precedence, because that’s actually the binding standard. The AMOP book itself stresses that the spec in its appendix is only a preliminary draft and not a final statement on how things should be. (Unfortunately, that statement isn’t included in the HTML version of the AMOP spec.)
On 17 Jan 2018, at 17:53, Didier Verna didier@lrde.epita.fr wrote:
Hi,
In the CLHS page for ENSURE-GENERIC-FUNCTION, there is this paragraph:
"If function-name specifies a generic function that has a different value for the :generic-function-class argument and if the new generic function class is compatible[1] with the old, change-class is called to change the class of the generic function; otherwise an error is signaled.”
Unfortunately, the CLHS doesn’t specify what the default value for :generic-function-class is, or what happens when the user doesn’t pass a value for :generic-function-class.
The CLHS entry for defgeneric, however, seems to suggest that if you leave out the :generic-function-class option in the defgeneric macro form, and the already existing generic function has a class other than standard-generic-function, its class remains unchanged. (This I would find unfortunate, because it would mean that the textual form that is “in effect” and the actual object class can be different from each other.)
In the AMOP however, one can read the following.
From the page on ENSURE-GENERIC-FUNCTION: "The behavior of this function is actually implemented by the generic function ensure-generic-function-using-class. When ensure-generic-function is called, it immediately calls ensure-generic-function-using-class and returns that result as its own."
And then from the page on ENSURE-GENERIC-FUNCTION-USING-CLASS: "If the class of the generic-function-or-nil argument is not the same as the class specified by the :generic-function-class argument, an error is signaled."
Let alone the fact that this should only apply when there actually is an existing generic function, this seems to be in contradiction with the Common Lisp standard, as it would explicitly forbid changing the class of the generic function, even in a "compatible" way.
Comments?
I don’t remember the exact details anymore why I arrived to that conclusion, because it’s some time ago by now, but my conclusion and strong recommendation is to stay away from ensure-generic-function, ensure-generic-funciton-using-class, and also ensure-class and ensure-class-using-class. My interpretation of the various specs for these is that they were supposed to be convenience functions for “end users”, imitating the effects of the corresponding macro versions, but trying to deal with too many corner cases at the same time which require different solutions, which is why they have these contradictory requirements and effects.
As far as I can tell, these functions provide nothing that can’t otherwise be expressed using more low-level means, including make-instance, initialize-instance, reinitialize-instance and change-class, which are much more cleanly specified and require a lot less guessing.
Both CLOS and the CLOS MOP could benefit from one or two more passes of careful specification fixes to make them more consistent, but I guess that’s not going to happen. :-(
Footnotes: [1] BTW, what does "compatible" mean ?
Well, the AMOP essentially specifies that generic function metaobject classes are always only compatible with themselves.
CLOS was accepted as part of ANSI CL long before there was reasonable draft version of the CLOS MOP available, so some of the forward references to the CLOS MOP spec that were added to CLtL2 survived in ANSI CL without double-checking them to make them compatible again with the then-exising AMOP book.
My guess is that it turned out that specifying what compatibility between generic function metaobject classes actually means was too hard, so they resorted to the easy way out. ;)
Pascal
-- Pascal Costanza
Pascal Costanza wrote:
Secondly, the general rule is: If there is a discrepancy between ANSI CL and AMOP, and ANSI CL has precedence, because that’s actually the binding standard.
Yup, and thanks for your (chronological) explanations.
I don’t remember the exact details anymore why I arrived to that conclusion, because it’s some time ago by now, but my conclusion and strong recommendation is to stay away from ensure-generic-function, ensure-generic-funciton-using-class, and also ensure-class and ensure-class-using-class. My interpretation of the various specs for these is that they were supposed to be convenience functions for “end users”, imitating the effects of the corresponding macro versions, but trying to deal with too many corner cases at the same time which require different solutions, which is why they have these contradictory requirements and effects.
I got the same feeling. It seems to me that the functional (public) layer had better been defined as just the equivalent of the macro one, or rather the opposite, with macros letting one use designators instead of object arguments, and avoiding the need for too much quoting as well.