In addition to what Patrick said, which is all right on the mark,
I'd like to point out a few additional subtleties.

Perl borrows an important idea from Lisp and separates the notion
of stack unwinding from that of exception handling; when you throw
an exception (including a control exception) you look for a handler
without unwinding the stack.  Only after you have determined which
handler handles the exception do you decide what to do with the
stack.  (Among other things, this lets you treat warnings as merely
a resumable form of exception, which lets you use exception handlers
to trap warnings propagating outward instead of inventing a separate
mechanism for that.  Non-destructive control flow also tends to be
friendlier to concurrency.)

Another things that's going on here is that Perl typically defines the
scope of a control exception to be first lexical if possible, and
dynamic otherwise.  What this comes down to practically is that next
LABEL will return from the loop you think it will return from, and not
some loop embedded in the call stack that happens to have the same
label.  But if there is no such label in your lexical outer scope, it
goes ahead and looks for it by chasing up the dynamic scopes.  Other
control forms may suppress the dynamic lookup entirely.

For example, return will always return from the lexically surrounding
sub or method, and never even try to return from some inner dynamic sub.

Because the control flow can in most cases be determined lexically,
the compiler can know when the branch target is in the same lexical
scope as the branch, and can optimize it to a simple branch if there
is no intermediate dynamic scoping that has to be unwound.

Even goto prefers a lexically scoped label over a dynamically
scoped on.  There are two wrinkles for implementing goto the
way Perl wants it.  First, you have to collect the labels in each
lexical scope and store them somewhere (along with their addresses)
in case someone wants to goto them from some inner dynamic scope.
(You can't just assume goto will come from an inner lexical scope,
unless the dynamic scoping is pragmatically suppressed.  Likewise a
next or last from a dynamic scope could be suppressed.)

The other wrinkle is a bit more subtle; for each lexical scope that
does not require initialization, you propagate the label set outward
to its outer scope, so that you can do a goto into any scope that
won't get confused by skipping its initialization (such as into a
conditional, or into the next branch of a switch).

Throwing a goto exception then mostly just means searching the
lexical scopes in the right order for one that knows the label, then
transferring the "real" control flow to that lexical scope so that
it can dispatch to the address associated with the label.

Again, these rules are such that goto (and next and last and return
and continue and break) can be optimized to a simple branch when it's
known that there's no dynamic interference.

One more caveat: since we're in CPS-land, when I say "unwinding the
stack", that is of course just shorthand for switching continuations;
it's really up to the GC to eventually destroy any unreferenced
stack bits.

Anyway, just trying to get everyone thinking the same things when we
use terms that could be misunderstood for historical reasons.  Perl 6
exceptions have very little resemblance to Perl 5 exceptions, so it's
easy to get muddled in terms.

Larry

Reply via email to