Calling another overloaded method in Lisp

280 views Asked by At

I couldn't find out if this was possible, and just used a (rather ugly) workaround.

Assume we've got a class structure as below:

(defclass a () ())
(defclass b (a) ())

and the method:

(defmethod print-object ((a1 a) stream)
 (format stream "instance of A "))

now, I want to call print for 'a then print for 'b, assuming a "type-cast" function exists:

(defmethod print-object ((b1 b) stream)
 (prin1 (type-cast b1 'a) stream)
 (format stream "instance of B "))

My workaround is to create an object of type a within print-object of b, then call prin1

(defmethod print-object ((b1 b) stream)
 (let ((a1 (make-instance 'a)))
    (prin1 a1 stream))
 (format stream "instance of B "))

I tried coerce and ended up with infinite loop. I just realized I can try using find-method and call-method (would it work?). Or should I try a solution with :around?

3

There are 3 answers

0
Rainer Joswig On BEST ANSWER

COERCE does not work with CLOS objects. You can change the class of an instance with CHANGE-CLASS, but that's usually not a good idea.

CALL-NEXT-METHOD

You can call the next applicable method: CALL-NEXT-METHOD. Note that you can't call a specific method that way, just the next one. Most of the time this is what one would use in CLOS. The task is then during method definition to set up the generic function in such a way, using primary, :around, :before and :after methods, that the right behavior emerges.

Calling specific functions when all else fails

There is an esoteric way to call a specific method:

(funcall (method-function (find-method #'print-object
                                       nil
                                       (list (find-class 'a)
                                             (find-class t))))
         (make-instance 'b)
         t)

In above code, the function METHOD-FUNCTION is not part of ANSI Common Lisp, but provided in many implementations by the Metaobject Protocol (MOP).

1
monoid On

Coerce doesn't create new object because b1 is already has type (subtype) of a already.

All you need is call-next-method:

(defmethod print-object ((a1 a) stream)
   (format stream "instance of A "))

(defmethod print-object ((b1 b) stream)
   (call-next-method) ; by default same arguments are used: b1 and stream
   (format stream "instance of B "))
0
user1597986 On

Following the example on process locks by Sonya Keene (Object-Oriented Programming in COMMON LISP: A Programmer's Guide to CLOS), you can use an :after method

(defmethod print-object ((a1 a) stream)
  (format stream "instance of A ")) 
(defmethod print-object :after ((b1 b) stream)
  (format stream "instance of B "))

This will give

CL-USER> (make-instance 'b)
    instance of A instance of B