21

How do you return early from a function before it's ended? For example:

(defun my-func () 
 "for example."
 (unless something (return nil))
 ; continue as usual...
 (+ 42 1))
0

2 Answers 2

8

In addition to what @EmacsFodder covered, just raise an error.

This will not help if the code is called within (dynamically, not lexically) the extent of error-handling constructs such as ignore-errors or condition-case, but otherwise it is a fine way to exit a function. It is in fact what is done most of the time.

(defun my-func () 
 "..."
 (unless something (error "Whoops!"))
 ; continue as usual...
 (+ 42 1))

If you want to handle the error yourself then you can put the calling code (e.g. the call to something that ulimately calls my-func) inside a condition-case. Again, this is what is done most of the time, at least as often as using catch + throw. It all depends on what behavior you want.

3
  • Thanks for the answer Drew, I agree this is quite a common method. However, just doing an early return in a lot of other languages, doesn't incur the complexity of having to then deal with an error. When researching the question/answer set. I was specifically looking for alternatives to the "erroring out" style which always feels kludgy to me. I didn't specify this explicitly in the question text mind you.
    – ocodo
    Commented Feb 1, 2015 at 1:00
  • 1
    It all depends on what you want to do. If you want to end immediately, with no further processing/handling, then raising an error is a good way to go for a nonlocal exit, in Emacs. If you want to do something during a nonlocal exit, i.e., handle it in some way, then catch, unwind-protect, condition-case and the like are useful. There is a whole section of the Elisp manual devoted to nonlocal exits. (And there is nothing particularly kludgy about any of them, IMO.)
    – Drew
    Commented Feb 1, 2015 at 2:54
  • "Feels" is entirely subjective of course. Thanks for the nonlocal manual ref.
    – ocodo
    Commented Feb 1, 2015 at 2:56
27

We have a number of options available. In general, what you are looking for is a "nonlocal exit"; see (info "(elisp) Nonlocal Exits").

Throw

You can catch / throw to exit the function with a value. See (info "(elisp) Catch and Throw") for details.

example:

(defun my-func ()
  "Simplistic `catch'/`throw' example."
  (catch 'my-early-return
    (when t
      (throw 'my-early-return "this is the short-circuit result of catch"))
    "this is the fallback result of catch"))

Block

You can also use cl-block and cl-return-from (although you will need to require cl-lib). See (info "(cl) Blocks and Exits") for details.

example:

(eval-when-compile
  (require 'cl-lib))

(defun my-func ()
  "Simplistic `cl-block'/`cl-return-from' example."
  (cl-block my-func
    (when t
      (cl-return-from my-func))
    (1+ 42)))

cl-defun

We also have cl-defun which has an implicit cl-block with the same name as the function, so we can use the cl-block style with less typing.

example:

(eval-when-compile
  (require 'cl-lib))

(cl-defun my-func ()
  "Simplistic `cl-defun' implicit block example."
  (when t
    (cl-return-from my-func)) ; `my-func' is an implicit block.
  (+ 42 1))

defun*

In old Emacsen, specifically Emacs 24.2 and earlier, cl-defun was provided as defun* by the now-obsolete library cl.el.

example:

(eval-when-compile
  (require 'cl))

(defun* my-func ()
  "Simplistic `defun*' implicit block example."
  (when t
    (return-from my-func)) ; `my-func' is an implicit block.
  (+ 42 1))

Note, however, that in Emacsen that old you can instead install cl-lib as a compatibility layer from GNU[-devel] ELPA:

1
  • 6
    Note that if you don't have a preference for the CL syntax, catch/throw is more idiomatic in elisp, as other approaches are ultimately implemented in terms of catch/throw. The elisp manual says: "Most other versions of Lisp, including Common Lisp, have several ways of transferring control nonsequentially: return, return-from, and go, for example. Emacs Lisp has only throw."
    – phils
    Commented Jan 31, 2015 at 5:28

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.