Apocalypse 4
All About Blocks
by Larry WallJanuary 15, 2002
This Apocalypse is all about syntax in the large. The corresponding chapter in the Camel book is entitled "Statements and Declarations", but it could just as easily have been entitled, "All About Blocks". The basic underlying question is "What exactly do those curlies mean?"
For Perl 5 and earlier, the answer to that question was, "Too many things". Or rather, too many things with inconsistent rules. We'll continue to use curlies for much of what we've used them for up till now, but by making a few critical simplifications, the rules will be much more consistent. In particular, built-ins will parse with the same rules as user-defined constructs. It should be possible to make user-extensible syntax look just like built-in syntax. Perl 5 started down this road, but didn't get all the way there. In Perl 6, all blocks operate under the same rules. Effectively, every block is a kind of closure that can be run by user-defined constructs as well as built-ins.
|
|
Associated with block structure are the various constructs that
make use of block structure. Compound constructs like loops and
conditionals use blocks explicitly, whereas declarations refer to
their enclosing block implicitly. This latter feature was also
inconsistently applied in Perl 5. In Perl 6, the rule is simple:
A lexically scoped declaration is in effect from the declaration to
the end of its enclosing block. Since blocks are delimited only
by curlies or by the ends of the current compilation unit (file or
string), that implies that we can't allow multi-block constructs in
which lexically scoped variables "leak" or "tunnel" from the end of
one block to the beginning of the next. A right curly (without an
intervening left curly) absolutely stops the current lexical scope.
This has direct bearing on some of these RFCs. For instance, RFC
88 proposes to let lexical scope leak from a try block into
its corresponding finally block. This will not be allowed.
(We'll find a different way to solve that particular issue.)
While lexical declarations may not leak out of a block, control flow
must be able to leak out of blocks in a controlled fashion. Obviously,
falling off the end of a block is the most "normal" way, but we need to
exit blocks in other "abnormal" ways as well. Perl 5 has several
different ways of exiting a block: return, next, last,
redo, and die, for instance. The problem is that these various
keywords are hard-wired to transfer control outward to a particular
built-in construct, such as a subroutine definition, a loop, or an
eval. That works against our unifying concept that every block is a
closure. In Perl 6, all these abnormal means of block exit are unified
under the concept of exceptions. A return is a funny kind of
exception that is trapped by a sub block. A next is an exception
that is trapped by a loop block. And of course die creates a
"normal" exception that is trapped by any block that chooses to trap such
exceptions. Perl 6 does not require that this block be an eval or
try block.
You may think that this generalization implies excessive overhead, since generally exception handling must work its way up the call stack looking for an appropriate handler. But any control flow exception can be optimized away to a "goto" internally when its target is obvious and there are no user-defined blocks to be exited in between. Most subroutine return and loop control operators will know which subroutine or loop they're exiting from because it'll be obvious from the surrounding lexical scope. However, if the current subroutine contains closures that are being interpreted elsewhere in user-defined functions, it's good to have the general exception mechanism so that all needed cleanup can be automatically accomplished and consistent semantics maintained. That is, we want user-defined closure handlers to stay out of the user's face in the same way that built-ins do. Control flow should pretend to work like the user expects, even when it doesn't.
Here are the RFCs covered in this Apocalypse. PSA stands for "problem,
solution, acceptance", my private rating of how this RFC will fit
into Perl 6. Interestingly, this time I've rejected more RFCs than
I accepted. I must be getting cruel and callous in my old age. :-)
RFC PSA Title
--- --- -----
006 acc Lexical variables made default
019 baa Rename the C<local> operator
022 abc Control flow: Builtin switch statement
063 rr Exception handling syntax
064 bdc New pragma 'scope' to change Perl's default scoping
083 aab Make constants look like variables
088 bbc Omnibus Structured Exception/Error Handling Mechanism
089 cdr Controllable Data Typing
106 dbr Yet another lexical variable proposal: lexical variables made default
113 rr Better constants and constant folding
119 bcr Object neutral error handling via exceptions
120 bcr Implicit counter in for statements, possibly $#
167 bcr Simplify do BLOCK Syntax
173 bcc Allow multiple loop variables in foreach statements
199 abb Short-circuiting built-in functions and user-defined subroutines
209 cdr Fuller integer support in Perl
262 cdr Index Attribute
279 cdr my() syntax extensions and attribute declarations
297 dcr Attributes for compiler hints
309 adr Allow keywords in sub prototypes
330 acc Global dynamic variables should remain the default
337 bcc Common attribute system to allow user-defined, extensible attributes
340 dcr with takes a context
342 bcr Pascal-like "with"


