I recently had to touch go and came to know about defer
statements which let you
stack few function calls for execution just before the parent function exits,
irrespective of how it actually exits. Something like this is also available in
R in the guise of on.exit
function. Here is an example from the chapter on
functions in Advanced R:
in_dir <- function(dir, code) { old <- setwd(dir) on.exit(setwd(old)) force(code) } getwd()
In an attempt to improve the defun
experience in Emacs Lisp, I tried replicating
the defer thing in a macro (also adding support for early return).
(defmacro defun+ (name lambda-list &optional docstring &rest body) "Regular defun with defer and return support" (let ((defers (make-symbol "defers"))) `(defun ,name ,lambda-list ,docstring (block nil ;; This lets us use return expression (let ((,defers nil)) (cl-macrolet ((defer (form) `(push '(funcall ,form) ,',defers))) (unwind-protect (progn ,@body) (eval `(progn ,@,defers)))))))))
Now, we can do things like:
(defun+ some-func (x y) "hello" (defer (lambda () (print "the last deferred expression"))) (defer (lambda () (print "second deferred"))) (print "hello world") (if nil (defer (lambda () (print "unevaluated deferred")))) (defer (lambda () (print "this will be evaluated first"))) (if t (return 33)) (+ x y)) (print (format "Finally, the returned value is %s" (some-func 1 2)))