Issue: FLET-IMPLICIT-BLOCKReference: CLtL p. 113, 67
Category: OMISSION
Edit history: Version 2 by cleanup committee 15-Mar-87 15:13:33
Version 3 by Masinter (reformatting) 7-Apr-87 17:49:12
Versions 4,5 by Fahlman 11-Apr-87
Version 6 by Masinter 5-Jun-87
Problem Description:
Do FLET, LABELS, DEFMACRO, MACROLET, DEFSETF, DEFINE-SETF-METHOD, and
DEFTYPE have an implicit block around their bodies like the body of a
DEFUN? CLtL is silent on this point. Many users and some implementors
assume that such blocks should be established, since they view these
forms as analogous with DEFUN.
Test case:
(defun test ()
(flet ((test (x) (if x (return-from test 4) 3)))
(test)
will return (3 4) if FLET-IMPLICIT-BLOCK:YES is adopted, and would
return 4 in an implementation that did not add an implicit block around
FLET.
Proposal: FLET-IMPLICIT-BLOCK:YES
Each function created by FLET and LABELS and each macro created by
DEFMACRO and MACROLET has an implicit block around the body. The name
of this block is that same as the (lexical) name of the function or
macro. Similarly, the body code in DEFSETF, DEFINE-SETF-METHOD, and
DEFTYPE is surrounded by a block with the same name as the accessor or
type.
Current Practice:
Current practice is mixed. Several implementations do not add the
implicit block, others do, some add some of these blocks and not others.
Cost of adopting this change:
Some implementations will have to be modified. This should be a
relatively easy modification.
Cost of not adopting the change:
If the issue is not clarified one way or another, continuing confusion
will result in portability problems. Clarifying the issue in any other
way would also require modifications in some implementations.
Cost of converting existing code:
It is possible that some user code would break because it does a return
from within a code body to an outer block that has the same as the
newly-required block. Such problems will be rare, and the code in
question would not run on all current Common Lisp systems because of the
diverse interpretations currently in effect. It would be possible to
detect all such instances automatically, though it seems unlikely that
anyone will need to use this technique.
Discussion:
The goal is first to clean up an ambiguous situation and, second, to do
this in a way that provides consistent behavior between local and global
definitions. The proposed change would allow a simple rule of thumb:
any named entity that takes a code body establishes an implicit block
with the obvious name.
Two alternatives to the proposal were considered and rejected:
The first would be to keep the implicit block in DEFUN, and to clearly
state that the other forms do not create implicit blocks. This violates
the goal of consistency between lexical and global definitions, and it
seems to conflict with users' expectations.
The second alternative was to eliminate the implicit block from DEFUN
rather than adding such blocks to other forms. There was some feeling
that specifying the implicit block in DEFUN was a poor design decision
in the first place, since it hides a reference to the name of a function
within the code of the function itself. If a user decides to rename
some function, he must be careful to rename any return-from forms within
the body of the function as well.
However, eliminating the implicit block in DEFUN would be a significant
incompatible change. Some users find this implicit block to be a great
convenience for popping out of convoluted code, and some existing code
makes heavy use of this feature. While such code could be repaired
automatically by searching for situations in which the user returns from
a function by name and by adding an appropriate explicit block to any
function containing such a forms, it would still require more more work
on existing user code than this proposal made above.
There was considerable discussion in the cleanup committee about whether
these implicit blocks would interfere with tail-recursion optimization,
which we hope will become more common in future Common Lisp
implementations. The outcome of these discussions was general agreement
that a compiler could easily eliminate the implicit block in any case
where it is not actually used, and that the impact on tail-recursion
optimization in compiled code is therefore minimal.