There is a generic method, say incx
. There are two versions of incx
. One specialized on type a
, and one specialized on type b
. Type b
is a subclass of a
. You are given an object of type b
, the derived type - but you want to call the method that is specialized on type a
. You could do this easily if there wasn't already a method of the same name specialized on type b
, but alas, there is such a method.
So how do you call the method specialized on type a
in such a situation?
(defclass a () ((x :accessor x :initform 0)))
(defclass b (a) ((y :accessor y :initform 0)))
(defgeneric inc (i))
(defmethod inc ((i a)) (incf (x i)))
(defmethod inc ((i b)) (incf (y i)))
(defvar r (make-instance 'b))
As promised by CLOS, this calls the most specialized method:
* (inc r)
* (describe r)
..
Slots with :INSTANCE allocation:
X = 0
Y = 1
But this in this particular case, (not in general) what I want is to access the less specialized version. Say something like:
(inc (r a)) ; crashes and burns of course, no function r or variable a
(inc a::r) ; of course there is no such scoping operator in CL
I see the call-next-method
function can be used from within a specialized method to get the next less specialized method, but that isn't what is wanted here.
In the code this was cut out of, I do need something similar to call-next-method
, but for calling a complementary method. Rather than calling a method of the same name in the next less specialized class, we need to call its complementary method, which has a different name. The complementary method is also specialized, but calling this specialized version doesn't work - for much the same reasons that call-next-method
was probably included for. It isn't always the case that the required method specialized on the super class has the same name.
(call-next-method my-complement) ; doesn't work, thinks my-complement is an arg
Here is another example.
There is a base class describing electron properties and a derived class describing the properties of a "strange-electron". Methods specialized on the strange electron desire to call methods specialized on the electron. Why? because these methods do the normal electron part of the work for the program. The non-electron part of the strange electron is almost trivial, or rather it would be if it didn't duplicate the electron code:
(defgeneric apply-velocity (particle velocity))
(defgeneric flip-spin (particle))
;;;; SIMPLE ELECTRONS
(defclass electron ()
((mass
:initform 9.11e-31
:accessor mass)
(spin
:initform -1
:accessor spin)))
(defmacro sq (x) `(* ,x ,x))
(defmethod apply-velocity ((particle electron) v)
;; stands in for a long formula/program we don't want to type again:
(setf (mass particle)
(* (mass particle) (sqrt (- 1 (sq (/ v 3e8)))))))
(defmethod flip-spin ((particle electron))
(setf (spin particle) (- (spin particle))))
;;;; STRANGE ELECTRONS
(defclass strange-electron (electron)
((hidden-state
:initform 1
:accessor hidden-state)))
(defmethod flip-spin ((particle strange-electron))
(cond
((= (hidden-state particle) 1)
(call-next-method)
;; CALL ELECTRON'S APPLY-VELOCITY HERE to update
;; the electron. But how???
)
(t nil)))
;; changing the velocity of strange electrons has linear affect!
;; it also flips the spin without reguard to the hidden state!
(defmethod apply-velocity ((particle strange-electron) v)
(setf (mass particle) (* (/ 8 10) (mass particle)))
;; CALL ELECTRON'S SPIN FLIP HERE - must be good performance,
;; as this occurs in critical loop code, i.e compiler needs to remove
;; fluff, not search inheritance lists at run time
)
It all reduces to a simple question:
How to call the less specialized method if a more specialized one has been defined?