That is not necessarily a problem, since a generic is allowed to take a
variable number of parameters. Here's how to go around that:
;; super-class
(defclass parent () ())
;; sub-class
(defclass child (parent) ())
;; mystery defined on parent (1 parameter version
(defmethod mystery ((object parent) &rest args)
(apply #'(lambda (x) (not x)) args))
;; mystery defined on child
(defmethod mystery ((object child) &rest args)
(apply #'(lambda (x y) (+ x y)) args))
;; inherited? _only_ defined on parent
(defmethod inherited? ((object parent) &rest args)
(apply #'(lambda () (format t "Answer: It was defined on class parent
~%" )) args))
(defparameter pobj (make-instance 'parent))
(defparameter cobj (make-instance 'child))
;; Here we call mystery with 1 parameter
(format t "(mystery pobj nil) -> ~A~%" (mystery pobj nil))
;; Here we call mystery with 2 parameters
(format t "(mystery cobj 2 3) -> ~A~%" (mystery cobj 2 3))
(format t "Question: Where was inherited defined for pobj? ")
(inherited? pobj)
(format t "Question: Where was inherited defined for cobj? ")
(inherited? cobj)
;; So what is this clunkyness with apply/lambda
;; Well, we can avoid it with macros
;; Unfortunately it only specializes on the first parameter
(defmacro defvirtual (name ((object class) &rest formals) &rest body)
`(defmethod ,name ((,object ,class) &rest args)
(apply #'(lambda ,formals ,@body) args)))
;; Now let's try it again
(defvirtual myth ((object parent) x)
(not x))
(defvirtual myth ((object child) x y)
(+ x y))
;; Here we call myth with 1 parameter
(format t "(myth pobj nil) -> ~A~%" (myth pobj nil))
;; Here we call myth with 2 parameters
(format t "(myth cobj 2 3) -> ~A~%" (myth cobj 2 3))
Homework:
Is there a way to call myth with 1 parameter on cobj and have it invoke the
pobj version? Modify defvirtual to achieve that. Even better, make
defvirtual optionally specialize on more than one parameter.
And just a note, you don't need defmethod or defgeneric at all, you can
create your own macros that operate on hash tables of "methods" and achieve
the functionality *you* need.
Jack Unrue wrote:
>
> As a practical matter, I'm saying that the different variations would
> not necessarily be congruent, and that is going to prevent defining
> this method in the way that I think you are intending. Whereas,
> within problem a domain, you probably will find that there is a
> class hierarchy where such methods would naturally be congruent.
>