Search code examples
lispcommon-lispevalblock

Parameterizable return-from in Common Lisp


I'm learning blocks in Common lisp and did this example to see how blocks and the return-from command work:

 (block b1 
            (print 1)
            (print 2)
            (print 3)
            (block b2 
                   (print 4)
                   (print 5)
                   (return-from b1)
                   (print 6)

               )
            (print 7))

It will print 1, 2, 3, 4, and 5, as expected. Changing the return-from to (return-from b2) it'll print 1, 2, 3, 4, 5, and 7, as one would expect.

Then I tried turn this into a function and paremetrize the label on the return-from:

 (defun test-block (arg)  (block b1 
            (print 1)
            (print 2)
            (print 3)
            (block b2 
                   (print 4)
                   (print 5)
                   (return-from (eval arg))
                   (print 6)

               )
            (print 7)))

and using (test-block 'b1) to see if it works, but it doesn't. Is there a way to do this without conditionals?


Solution

  • Using a conditional like CASE to select a block to return from

    The recommended way to do it is using case or similar. Common Lisp does not support computed returns from blocks. It also does not support computed gos.

    Using a case conditional expression:

    (defun test-block (arg)
      (block b1 
        (print 1)
        (print 2)
        (print 3)
        (block b2 
          (print 4)
          (print 5)
          (case arg
            (b1 (return-from b1))
            (b2 (return-from b2)))
          (print 6))
        (print 7)))
    

    One can't compute lexical go tags, return blocks or local functions from names

    CLTL2 says about the restriction for the go construct:

    Compatibility note: The ``computed go'' feature of MacLisp is not supported. The syntax of a computed go is idiosyncratic, and the feature is not supported by Lisp Machine Lisp, NIL (New Implementation of Lisp), or Interlisp. The computed go has been infrequently used in MacLisp anyway and is easily simulated with no loss of efficiency by using a case statement each of whose clauses performs a (non-computed) go.

    Since features like go and return-from are lexically scoped constructs, computing the targets is not supported. Common Lisp has no way to access lexical environments at runtime and query those. This is for example also not supported for local functions. One can't take a name and ask for a function object with that name in some lexical environment.

    Dynamic alternative: CATCH and THROW

    The typically less efficient and dynamically scoped alternative is catch and throw. There the tags are computed.