12

Is it possible to break out of a dolist loop? if not, are there alternatives to dolist that don't involve a while loop and indexing a list?

4
  • Pitingly, the while loop is excluded. IMHO it is the only pre-defined loop avoiding non-local exit when breaking out of a list iteration. It can be head or tail controlled or anything in between.
    – Tobias
    Nov 13, 2019 at 7:31
  • BTW you added The catch statement evaluates to the value thrown (x in this case), or nil if no value is thrown. to lawlist's answer. How do you throw without passing a value? The VALUE arg of throw is obligatory. Maybe, you mean cl-return where it is optional.
    – Tobias
    Nov 13, 2019 at 7:33
  • @Tobias it was poor wording, now corrected.
    – ideasman42
    Nov 13, 2019 at 8:28
  • I've expanded it a bit further to avoid any misunderstandings.
    – Tobias
    Nov 13, 2019 at 8:54

2 Answers 2

14

One option is to use catch / throw:

https://www.gnu.org/software/emacs/manual/html_node/elisp/Catch-and-Throw.html

(catch 'foo
  (dolist (x '("a" "b" "c" "d" "e" "f" "g"))
    (when (equal x "d")
      (throw 'foo x))))

The catch statement evaluates to the value thrown (x in this case), or the value of the last body form if the throw function never executes. In the case at hand the dolist form is the last entry in the body. The optional RESULT argument of (dolist (VAR LIST [RESULT]) BODY...) is not specified. Therefore, it evaluates to nil.


As pointed out by @Drew and @Tobias in comments below, the dolist function that is available without loading the cl library is defined in subr.el. Once the cl library is loaded, however, describing the function with C-h f reflects that dolist has been modified as follows: :around advice: ‘cl--wrap-in-nil-block’. The function return (which is an alias for cl-return that is defined in the cl library) can be used to break the dolist loop. To load the cl library, begin with (require 'cl):

(dolist (x '("a" "b" "c" "d" "e" "f" "g"))
  (when (equal x "d")
    (return x)))
7
  • 2
    +1. Maybe make clearer that without loading library cl the version of dolist is different (not an alias for cl-dolist). You can use return (cl-return) only with the version of dolist provided by library cl (it is an alias for cl-dolist). You more or less say that, but it could be clearer - there are two different dolists, and only one lets you use return.
    – Drew
    Nov 13, 2019 at 5:05
  • 1
    @Drew dolist is never an alias for cl-dolist. cl.el rather wraps dolist into a nil-block by an around advice and (cl-return val) is essentially (throw nil val). So there is not much difference between the two solutions of lawlist. The second solution is just more elegant if cl is available.
    – Tobias
    Nov 13, 2019 at 5:55
  • 1
    Do not require cl. That is depreciated. Better require cl-macs or cl-lib and use cl-dolist and cl-return instead of dolist and return. Maybe, explicitly state that and give both alternative solutions.
    – Tobias
    Nov 13, 2019 at 6:03
  • 1
    Citation from the cl info file: "Since the old cl.el does not use a clean namespace, Emacs has a policy that packages distributed with Emacs must not load cl at run time. (It is ok for them to load cl at compile time, with eval-when-compile, and use the macros it provides.) There is no such restriction on the use of cl-lib. New code should use cl-lib rather than cl."
    – Tobias
    Nov 13, 2019 at 6:33
  • 1
    @lawlist here is the thread about cl.el = declaring obsolete: emacs.1067599.n8.nabble.com/…
    – Hubisan
    Nov 13, 2019 at 9:23
0

The Common Lisp Cookbook has an extensive section on loops. Among other things, as a substitute for dolist you could try a "for" loop and use "when" to exit. For example:

(require 'cl-lib)
(cl-loop for i in '(123 3 22 1 309)
  when (< i 2)
    return -500
  do (print i))

... output ...

123 
3 
22 
-500

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.