Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to require keyword arguments in Common Lisp?

Given

(defun show-arg (a)
  (format t "a is ~a~%" a))

(defun show-key (&key a)
  (format t "a is ~a~%" a))

evaluating

(show-arg)

will lead to an error saying "invalid number of arguments: 0", where

(show-key)

will display a is NIL

How can I get SHOW-KEY to signal an error like SHOW-ARG does? Is there a way other than using (unless a (error "a is required")) in the function body? I am very fond of keyword arguments and use them constantly, and almost always want them to be required.

like image 659
Dan Passaro Avatar asked Dec 02 '22 14:12

Dan Passaro


2 Answers

Keyword arguments are always optional, so you do need to manually check if they're given and signal an error if needed. It would be better to not require keyword arguments though. The compiler won't recognize them as required and thus won't given you an error message for missing arguments at compile time.

If you do want to require them, you can specify the arguments with a three element list; the first element being the argument, the second is the default value and the third is a variable that will be true if the argument was given. Checking the third element is better than checking the keyword itself, because then you can tell the difference between a NIL that was the default, and a NIL that the user gave as an argument.

(defun foo (&key (keyarg nil keyargp))
  (unless keyargp (error "KEYARG is required."))
  (* keyarg 2))

Edit

Now that I think about this a bit more, there actually is a way to get compile time errors for missing keyword arguments. Define a compiler macro for the function:

(defun foo (&key a b c d)
  (* a b c d))

(define-compiler-macro foo (&whole whole &key (a nil ap) (b nil bp)
                                   (c nil cp) (d nil dp))
  (declare (ignore a b c d))
  (unless (and ap bp cp dp)
    (error "Missing arguments..."))
  whole)
like image 128
jkiiski Avatar answered Dec 26 '22 19:12

jkiiski


One possibility would be:

(defun foo (&key (arg1 (error "missing arg1 in call to function foo")))
   arg1)

Using it:

CL-USER 80 > (foo)

Error: missing arg1 in call to function foo
  1 (abort) Return to level 0.
  2 Return to top loop level 0.

This will give an error at runtime, unfortunately not at compile time.

like image 41
Rainer Joswig Avatar answered Dec 26 '22 17:12

Rainer Joswig