39

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?

Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
Matthew Piziak
  • 5,958
  • 3
  • 29
  • 77

2 Answers2

37

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)))
glucas
  • 20,175
  • 1
  • 51
  • 83
  • 10
    -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. –  Jul 23 '15 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 Jul 23 '15 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. –  Jul 23 '15 at 21:09
  • 1
    this also doesnt allow for the optional being pass in as nil – RichieHH Mar 02 '20 at 20:01
29

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.

legoscia
  • 6,012
  • 29
  • 54