[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

around method for make-instance

Thomas Russ (tar@isi.edu) writes:
> In article <...> djskrien@COLBY.EDU (Dale J. Skrien) writes:
>  >
>  > Is there something special about putting methods
>  > around the make-instance primary method?
>  >  ...
>  > But when I define:
>  >
>  >     (defmethod make-instance :around
>  >                ((x foo) &rest initargs)
>  >       (let ((instance (call-next-method)))
>  >           (list instance)))
>  >
>  > then I get:
>  >
>  > ? (make-instance 'foo)
>  >    => #<FOO #x17E44F1>
>  >
>  > Shouldn't I have gotten:
>  >      (#<FOO #x17E44F1>)
>  >
> Because the argument to make-instance, 'foo, is of type SYMBOL, not of
> class FOO!  You would need to have the method specialized on (eql 'foo):
>      (defmethod make-instance :around
>                 ((x (eql 'foo)) &rest initargs)
>        (let ((instance (call-next-method)))
>            (list instance)))

This will work, of course, but it will fail if you actually send a
class to make-instance, like this:
(make-instance (find-class 'foo)).

A more general solution would be to have the lambda list look like this:
	((x (eql (find-class 'foo))) &rest initargs)
This will do what you want whether you do
(make-instance 'foo)
(make-instance (find-class 'foo))

Making lambda lists for methods that take classes like this 
as arguments is tricky. Remember that any method is called with an instance
as an argument, always. But when you do the defmethod, the specializer must
either be the class of the instance you wish to call the method on, or it
must be "(eql xxx)", where xxx is a _specific_ instance.
So methods are always called on instances, but defmethods may be defined
on either classes or instances.
Since make-instance and other methods are called with classes, this seems
like a contradiction. But it's not...the classes you call make-instance with
are _instances_ of the metaclass standard-class, so everything is fine.
If you wanted to override make-instance globally, you could just specialize
it on standard-class and the syntax would be just like normal lambda-list
syntax. (Kids: don't try this at home!)
But if you just want to specialize make-instance (or any other method that
takes a class as an argument) for a _single_ class, you have to use the
(eql...) syntax because you're then defining a method on a single instance
[of a metaclass].

Reading back over this, it looks clear as mud. Sorry. Maybe someone else
can explain it better.

-Shannon Spires