http://axisofeval.blogspot.com/2024/01/common-lisps-block-return-from-and.html skip to main | skip to sidebar The Axis of Eval Manuel Simoni's blog about programming (languages). Sunday, January 7, 2024 Common Lisp's BLOCK / RETURN-FROM and UNWIND-PROTECT I was just chatting with Ben Titzer on Twitter about control flow in his Virgil language (which is cool and you should definitely check out), when I felt the need to once more promote how Common Lisp does non-local control flow (stuff like returning early from a function or breaking from a loop), because I think it's a very nice solution. So in Common Lisp we have BLOCK / RETURN-FROM (which work as a pair) and UNWIND-PROTECT. BLOCK / RETURN-FROM BLOCK and RETURN-FROM effectively offer the same functionality as C's setjmp/longjmp -- non-local exits -- but nicely wrapped as we expect it in a lexically-scoped, expression-oriented language. BLOCK / RETURN-FROM lets you do: * Early returns from functions or arbitrary code blocks * Breaking from loops, including any number of nested loops * Continuing in loops, including any number of nested loops * Even arbitrary GOTOs in a code block (with some macrology & trampolining, see Baker's TAGBODY) (block name forms*) lexically binds name within the forms as a non-local exit from which you can return a value with (return-from name value). Just (return-from name) without a value uses nil as the value. A BLOCK without any RETURN-FROM just returns the last value: (block b 1 2 3) returns 3. This prints 1 and returns 2: (block b (print 1) (return-from b 2) (print 3)) You can have any number of nested blocks: (block b1 ... (block b2 ... (return-from b1) ...) ...) To do an early return from a function, place a block at its beginning: (defun foo () (block b ... (return-from b) ...)) (Common Lisp automatically places an anonymous block around every function body, so you don't need to do this in practice, but my hobby Lisp doesn't, and I'm using this explicit approach, and I like it.) To break from a loop, place a block around it: (block break (loop ... (return-from break) ...)) To continue in a loop, place a block inside it: (loop (block continue ... (return-from continue) ...)) You can have multiple nested loops, like in Java: (block break-outer (loop (block break-inner (loop ... (return-from break-inner) ...)))) UNWIND-PROTECT UNWIND-PROTECT is effectively a try/finally block (without a catch). (unwind-protect protected-form cleanup-forms*) evaluates the protected form, and regardless of whether it returns normally or does a non-local exit with RETURN-FROM, the cleanup forms are evaluated. (unwind-protect (foo) (bar) (quux)) is analogous to try { return foo(); } finally { bar(); quux(); } Both of the following expressions print 2 and return 1: (unwind-protect 1 (print 2)) (block exit (unwind-protect (return-from exit 1) (print 2))) Conclusion Common Lisp's BLOCK / RETURN-FROM and UNWIND-PROTECT offer a minimalistic and expressive system for non-local control flow. (Lobsters, HN) Posted by Manuel Simoni at 20:13 # Labels: lisp No comments: Post a Comment Older Post Home Subscribe to: Post Comments (Atom) Elsewhere @msimoni github.com/manuel Archives * V 2024 (1) + V January (1) o Common Lisp's BLOCK / RETURN-FROM and UNWIND-PROTECT * > 2016 (2) + > July (1) + > May (1) * > 2015 (4) + > August (1) + > July (1) + > June (2) * > 2014 (2) + > June (2) * > 2013 (8) + > June (1) + > May (4) + > April (1) + > February (1) + > January (1) * > 2012 (85) + > November (11) + > September (5) + > August (8) + > July (23) + > June (2) + > May (4) + > April (9) + > March (13) + > February (2) + > January (8) * > 2011 (94) + > December (5) + > November (5) + > October (5) + > September (7) + > August (13) + > July (9) + > June (7) + > May (9) + > April (9) + > March (9) + > February (6) + > January (10) * > 2010 (102) + > December (9) + > November (8) + > October (5) + > September (13) + > August (7) + > July (16) + > June (22) + > May (14) + > April (8) Linkroll * Alarming Development * Alex Payne -- Online Writing * Arcane Sentiment * Awelon Blue * blog.might.net * Dependent Types Reddit * Dynamic Aspects * eighty-twenty * Existential Type * Hack the Planet * HXA7241 * Kazimir Majorinc's Lisp Notes * Lambda the Ultimate * Linux Weekly News * Loper OS * Luke Gorrie's weblog * Making it stick. * One Mistake After Another * Paul Graham * Paul Snively's Blog * Philosophy Made Manifest * PiLuD: Programming Language Design * Proggit * Real World Technologies Forums * Send More Paramedics * State of Code * Stevey's Blog Rants * Structural insight * Subvert the dominant paradigm * Taylor Campbell's blag * The BileBlog * The ByteBaker * Trivium * Ward's wiki * wingolog