13

Is it possible to assign multiple return values directly to variables without going through a temporary variable in Emacs Lisp?

For example, let's say I have a function that returns a list of two lists:

(defun test-func ()
  (setq a '(a b))
  (setq b '(c d))
  `(,a ,b))

If I want to assign the first return value to list-a and the second return value to list-b, I can do this by using a temporary variable temp, for example:

(let* ((temp (test-func)) (list-a (car temp)) (list-b (cadr temp)))
  (message-box (prin1-to-string list-a))
  (message-box (prin1-to-string list-b)))

Is it possible to do this more simply? (I am used to Perl and Python where you do not have to specify a temporary variable)

2
  • 2
    You may try cl-destructuring-bind macro. Also, did you really intend to use setq inside a defun? setq creates a "special" (globally accessible) variable, something you'd typically put outside a function (because there's little meaning in declaring the same variable more than once, while functions are intended to be run more than once).
    – wvxvw
    Jan 26, 2015 at 10:54
  • @wvxvw Thanks! Yes I forgot to use let inside the function.. I did not plan to set any global variables :) Jan 26, 2015 at 11:23

2 Answers 2

8

Common Lisp has a special facility - multiple values, and Emacs Lisp compatibility library emulates them using lists.

Thus you can do

(defun test-fun ()
  (let ((a 1) (b 2))
    (cl-values a b)))

(cl-multiple-value-bind (a b) (test-fun)
  ...)

(load cl-lib and use the cl- prefix for all CL functionality in EL).

NB: if you look at the SO answer linked above, you will see that emulating MV with lists is, to put it mildly, suboptimal (see also @Stefan's comment below).

3
  • Is there any advantage of using multiple-value-bind instead of cl-multiple-value-bind (only the latter seems to be documented in the manual gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html ) ? Jan 26, 2015 at 11:50
  • 3
    @HåkonHægland They are the same function, but you should use the latter. The cl package is not meant to be used anymore. You should always use the cl-lib package instead, which defines functions with the cl- prefix..
    – Malabarba
    Jan 26, 2015 at 11:54
  • 1
    I'd recommend against the use of cl-values: it's a "best effort" emulation of CommonLisp's values but it's not really compatible since all it does is return a list (i.e. it's kind of a lie), and in my experience people sooner or later end up manipulating those as lists (i.e. breaking the abstraction): better use lists explicitly (and if you don't like pcase-let, then use cl-destructuring-bind rather than cl-multiple-value-bind).
    – Stefan
    Jul 9, 2018 at 15:59
5

Beside relying on the cl-lib compatibility package, the recommended way in Elisp for that is to use pcase:

(defun test-fun
  (let ((a '(a b))
        (b '(c d)))
    `(,a ,b)))

(defun other-test-fun ()
  (pcase-let ((`(,a ,b) (test-fun)))
    (message "a = %s; b = %s" a b)))

Beside pcase-let, there's also pcase-dolist, pcase-lambda, and pcase itself.

Your Answer

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

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