On 2 Aug 2006, at 17:59, Christophe Rhodes wrote:
> Pascal Costanza <pc@...> writes:
>> On 2 Aug 2006, at 15:19, Christophe Rhodes wrote:
>>> I don't see any value in the global default as specified (by AMOP;
>>> ANSI does not specify a default), since I would imagine that far and
>>> away most callers of ensure-generic-function don't actually want to
>>> change the class of the generic function if it already exists.
>> Most importantly, ensure-generic-function is the functional
>> of defgeneric. Consider you have the following definition:
>> (defgeneric foo (x)
>> (:generic-function-class my-generic-function))
>> ...and later on this is changed to:
>> (defgeneric foo (x))
>> ...you want the class of #'foo to be changed to standard-generic-
>> function (or alternatively see an error signalled).
> That's true, and I hadn't thought of that. But I'm not sure that it
> invalidates my argument: I'd be happy for DEFGENERIC to provide
> :generic-function-class 'standard-generic-function to
> ensure-generic-function, if it has no explicit :generic-function-class
But here, the CLOS MOP specification is surprisingly unambiguous. It
states that "for each of the options :argument-precedence-
order, :documentation, :generic-function-class and :method-class, the
value of the option becomes the value of the keyword argument with
the same name. If the option does not appear in the macro form, the
keyword argument does not appear in the resulting call to ensure-
>>> This means that callers must perform contortions of the above form
>>> to get
>>> hold of the generic function class to pass to ensure-generic-
>>> but, um, to do that, you have to get hold of the generic function
>>> itself, so why bother calling ensure-generic-function in the first
>>> place? (Sure, reinitializing it with different initargs, but you
>>> do that with reinitialize-instance).
>> Ensuring that the generic function is accessible via the specified
>> name and ensuring that the error checks are performed (when a
>> function or macro of that name already exists).
> Well, yes, but if you want to preserve any existing class of a generic
> function, you have to do almost all of that anyway. Certainly the
> ensuring that the generic function is accessible by the given name
> needs to be done to get hold of any existing class, and any attempt to
> reinitialize a macro-function isn't going to go terribly far ;-)
:) But this is implementation-dependent. The type 'macro-function
could be implemented by a CLOS class. OK, not too likely, but just
calling reinitialize-instance without any preceding checks seems
>> My take on this is that ensure-generic-function is simply overloaded
>> (in the non-technical sense of the term). A separation into ensure-
>> generic-function and ensure-method may have been a better idea.
> Ah, but I've just realised to my horror that it's not just
> ensure-generic-function that suffers from this; ensure-class does too.
> It's specified to have an unconditional default of standard-class for
> the :metaclass argument. I'm afraid I think that this is wrong (in
> the sense of "strongly suboptimal"), too, for exactly the same
> reasons; DEFCLASS can pass an explicit :metaclass 'standard-class if
> no metaclass is specified, but there's no way to get hold of the
> metaclass of an existing class without doing most of the work of
> ensure-class in the first place. So, again, I would suggest that the
> (class t) method of ensure-class-using-class defaults its :metaclass
> argument using the class of the class argument, and that defclass
> (along with defgeneric) provide explicit metaclasses in their
> expansion in all cases.
In the case of ensure-class, I don't see the problem. For
programmatic access to class metaobjects, you typically use find-
class, not ensure-class. I think it's really important that the
ensure-xyz functions are really only there to provide the
programmatic equivalent to defclass/defgeneric/defmethod, not as the
regular means to get hold of class/function/method metaobjects. Like
find-class, you can as well use fdefinition to access a generic
function, and even (setf fdefinition) to define one. For example,
note that in the code example for "Initialization of Generic Function
and Method Metaobjects" in the CLOS MOP spec, ensure-generic-function
is not used.
This whole issue is further complicated by the fact that defmethod
can implicitly create a generic function if there isn't one.
Finally, I don't see what the use of ensure-class-using-class and
- There is no way to reliably specialize these generic functions
without violating the rules for portable code. The only argument you
can specialize is the first one (class or generic-function), but they
are passed NIL when the functions are first called for a given class/
function. In portable programs, you are not allowed to specialize on
NIL/NULL. So the only reliable thing you can do is to specialize them
for redefinition of the respective metaobjects.
- However, reinitialization is already properly handled in
reinitialize-instance, where it is straightforward to define methods
on the respective metaobject classes. Same goes for initialize-instance.
So if you'd ask me, I'd just drop the ensure-xyz-using-class
functions, merge the descriptions with the main ensure-xyz functions,
so in effect forget about being able to specialize them, and in this
way make it clear that it's just the programmatic access to defclass/
defgeneric/defmethod. It'd still be useful to be able to indicate
that you don't want to change the class of the respective metaobject,
but at least the problem space would be narrowed.
> For what it's worth, existing practice as far as I know it:
> * SBCL -- effectively as I already describe, though the actual logic
> in argument passing is slightly different. Uses
> (ensure-class name) and (ensure-generic-function name) to
> return an existing (unchanged) class/gf of that name or a
> newly-created one with the standard metaclass.
> [ probably also CMUCL ]
> * Clisp -- explicitly passes standard-class and
> standard-generic-function in macroexpansions of defclass
> and defgeneric. Does not call ensure-generic-function from
> defmethod, or ensure-class from anywhere; conforms to AMOP
> as specified with respect to :metaclass and
> :generic-function-class behaviour.
> * ACL -- does not change class on ensure-class with no metaclass. (I
> haven't investigated further than this).
> (The picture that I think this paints is that there is no overall
> consensus on this issue.)
...which I'd interpret as: this is not used a lot, otherwise people
would complain more.
Pascal Costanza, mailto:pc@..., http://p-cos.net
Vrije Universiteit Brussel, Programming Technology Lab
Pleinlaan 2, B-1050 Brussel, Belgium