42

Emacs Lisp does not have syntactical support for non-nil defaults of optional parameters. What is the recommended idiom for supplying these parameters?

To clarify my point, here is one overly explicit way of doing so.

(defun command (a &optional supplied-b)
  (let ((b (or supplied-b default-b)))
    (command-body a b)))

What, if anything, is the recommended style?

2 Answers 2

39

Unless you use Common Lisp extensions as suggested by @legoscia, you need to check if the optional argument was specified. Note that you don't really need to use let here. This seems more idiomatic to me:

(defun command (a &optional b)
  (or b (setq b default))
  (command-body a b))

As suggested in the comments, using unless may be preferable to or:

(defun command (a &optional b)
  (unless b (setq b default))
  (command-body a b))

Also from the comments: the more pure functional style would be to use let, as in the original question, but you don't need separate variable names:

(defun my-command (a &optional b)
  (let ((b (or b default)))
    (command-body a b)))

Of course, if the optional parameter is only needed once you should just do this:

(defun my-command (a &optional b)
    (command-body a (or b default)))
4
  • 11
    -1: I don't think that it's good style to use a side-effecting expression like setq in a “pure” boolean form like or. In my opinion when is definitely more appropriate here, but generally let is the expression of choice to establish or change local bindings. IOW, the original code looks much nicer to me.
    – user227
    Commented Jul 23, 2015 at 20:46
  • 4
    I agree that something like (unless b (setq b default) might be better. Personally, I think let is redundant here because b is already local to the defun.
    – glucas
    Commented Jul 23, 2015 at 20:59
  • 4
    It's a matter of taste, but I prefer pure code and pure bindings, i.e. let over a side-effecting form like setq. It's code for a parameter default, but liberal use of setq to change local variables makes code hard to read and to follow. I think it's best to consider all local bindings immutable, and only establish new bindings with let. IOW, prefer a functional style over an imperative one.
    – user227
    Commented Jul 23, 2015 at 21:09
  • 2
    this also doesnt allow for the optional being pass in as nil
    – RichieHH
    Commented Mar 2, 2020 at 20:01
31

You can use cl-defun, which lets you specify a default value for optional arguments:

(cl-defun command (a &optional (b default-b))
  (command-body a b))

The default value, in this case default-b, will be evaluated every time the function is called.

1
  • dont forget to (require 'cl-macs)
    – malcook
    Commented May 25, 2022 at 21:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.