Reputation: 4861
Consider the class account
:
(defclass account ()
((name :initarg :name :reader name)
(balance :initarg :balance :initform 0.00 :accessor balance)
(interest-rate :allocation :class :initform 0.06
:reader interest-rate)))
For this class, we define a method withdraw
:
(defmethod withdraw ((acct account) amt)
(if (< amt (balance acct))
(decf (balance acct) amt)
'insufficient-funds))
And, another class password-account
, that is a subclass of account
:
(defclass password-account (account)
((password :initarg :password :reader password )))
And, the method withdraw
, for this class:
(defmethod withdraw ((acct password-account) amt pass)
(if (equal (password acct) pass)
(call-next-method acct amt )
'wrong-password))
But this gives an error :
The generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::WITHDRAW (1)>
takes 2 required arguments; was asked to find a method with
specializers
(#<STANDARD-CLASS COMMON-LISP-USER::PASSWORD-ACCOUNT>
#1=#<SB-PCL:SYSTEM-CLASS COMMON-LISP:T> #1#)
[Condition of type SB-PCL::FIND-METHOD-LENGTH-MISMATCH]
See also:
Common Lisp Hyperspec, FIND-METHOD [:function]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {1005308033}>)
Why is this happening? And what does
was asked to find a method with specializers
mean here?
Here, the primary withdraw
function had two arguments acct
and amt
, so in order to call it from a more specific method, which uses 3 arguments instead of 2, we can provide call-next-method
with the arguments of the less specific withdraw
method. But this still isn't working.
Any help appreciated.
Upvotes: 0
Views: 173
Reputation: 139261
Congruent lambda lists for generic functions
Methods of a generic function need to have congruent lambda lists. The language standard describes what that means: Congruent Lambda-lists for all Methods of a Generic Function.
As you can see the first rule says:
Required parameters tell us which arguments always have to be provided. Generic functions additionally allow optional, keyword and rest arguments. But there is no dispatch over these. The dispatch only works over the required arguments and all of those.
Having the same number of required parameters makes dispatch easier and allows the compiler to check for function calls with the wrong number of arguments.
Optional parameters need to be congruent, too
Note also that all methods of a generic function need to have the same number of optional parameters. See the second rule in the standard.
Wording
Examples:
(defun foo (a b) (list a b))
a
and b
are parameters for the function foo
.
(foo (+ 2 3) (* 4 5))
5
and 20
are the two arguments for the call of the function foo
.
Upvotes: 7