Author: lwall
Date: 2009-05-30 00:50:49 +0200 (Sat, 30 May 2009)
New Revision: 26968

Modified:
   docs/Perl6/Spec/S04-control.pod
Log:
[S04] expand on C<$!> semantics, remove requirement for GC on block exit


Modified: docs/Perl6/Spec/S04-control.pod
===================================================================
--- docs/Perl6/Spec/S04-control.pod     2009-05-29 14:29:27 UTC (rev 26967)
+++ docs/Perl6/Spec/S04-control.pod     2009-05-29 22:50:49 UTC (rev 26968)
@@ -12,8 +12,8 @@
 
   Maintainer: Larry Wall <la...@wall.org>
   Date: 19 Aug 2004
-  Last Modified: 25 May 2009
-  Version: 78
+  Last Modified: 29 May 2009
+  Version: 79
 
 This document summarizes Apocalypse 4, which covers the block and
 statement syntax of Perl.
@@ -1015,41 +1015,79 @@
 
 =head1 Exceptions
 
-As in Perl 5, many built-in functions simply return C<undef> when you ask
-for a value out of range, or the function fails somehow.  Perl 6 has
-C<Failure> objects, any of which refers to an unthrown C<Exception> object in
-C<$!> and knows whether it has been handled or not.
+As in Perl 5, many built-in functions simply return C<undef> when you
+ask for a value out of range, or the function fails somehow.  Perl 6
+has C<Failure> objects, any of which refers to an unthrown C<Exception>
+object in C<$!> and knows whether it has been handled or not.  C<$!>
+contains one main exception, the most recent, plus an internal list
+of unhandled exceptions that may be accessed via the C<.pending> method.
+Whenever a new exceptions is stored in C<$!>, it becomes the new main
+exception, and if the old main exception is not marked as handled,
+it is pushed onto the internal list of unhandled exceptions.
 
 If you test a C<Failure> for C<.defined> or C<.true>, it causes C<$!>
-to mark the exception as I<handled>; the exception acts as a relatively 
harmless
-undefined value thereafter.  Any other use of the C<Failure> object to
-extract a normal value will throw its associated exception immediately.
-(The C<Failure> may, however, be stored in any container whose type
-allows the C<Failure> role to be mixed in.)  The C<.handled> method
-returns C<False> on failures that have not been handled.  It returns C<True> 
for
-handled exceptions and for all non-C<Failure> objects. (That is,
-it is an C<Object> method, not a C<Failure> method.  Only C<Failure> objects
-need to store the actual status however; other types just return C<True>.)
+to mark the main exception as I<handled>; the exception acts as a
+relatively harmless undefined value thereafter.  Any other use of the
+C<Failure> object to extract a normal value will throw its associated
+exception immediately.  (The C<Failure> may, however, be stored in
+any container whose type allows the C<Failure> role to be mixed in.)
+The C<.handled> method returns C<False> on failures that have not
+been handled.  It returns C<True> for handled exceptions and for
+all non-C<Failure> objects. (That is, it is an C<Object> method,
+not a C<Failure> method.  Only C<Failure> objects need to store the
+actual status however; other types just return C<True>.)
 
-Because the contextual variable C<$!> contains all exceptions collected in the
-current lexical scope, saying C<die $!> will throw all exceptions,
-whether they were handled or not.  A bare C<die>/C<fail> takes C<$!> as the
-default argument.
+The C<.handled> method is C<rw>, so you may mark an exception as handled
+by assigning C<True> to it.  Note however that
 
-At scope exit, C<$!> discards all handled exceptions from itself, then performs
-a garbage-collection check for all remaining (unhandled) exceptions.  If all of
-them are still alive (e.g. by becoming part of the return value), then they are
-appended to C<< CALLER::<$!> >>.  Otherwise, it calls C<die> to throw those
-exceptions as a single new exception, which may then be caught with a C<CATCH>
-block in the current (or caller's) scope.
+    $!.handled = 1;
 
+marks only the main exception as handled.  To mark them all as handled
+you must access them individually via the C<.pending> method.
+
+A bare C<die>/C<fail> takes C<$!> as the default argument specifying
+the exception to be thrown or propagated outward to the caller's C<$!>.
+
+Because the contextual variable C<$!> contains all exceptions collected
+in the current lexical scope, saying C<die $!> will rethrow all those
+exceptions as the new thrown exception, keeping the same structure of
+main exception and list of unhandled exceptions.  (The C<$!> seen in a
+C<CATCH> block is specially bound to this in-flight exception as the
+blocks initial value for C<$!>, but it may be modified by additional
+failures as can any other block's C<$!> value.)  A C<fail> likewise
+moves all C<$!> exceptions up into C<< CALLER::<$!> >> before
+returning the current exception as normal return of a C<Failure>.
+
+At scope exit, C<$!> discards all handled exceptions from itself,
+then if there are any remaining unhandled exceptions, either as the
+main exception or as any listed unhandled exception, it calls C<die>
+to throw those exceptions as a single new exception, which may then
+be caught with a C<CATCH> block in the current (or caller's) scope.
+The new main exception is the most recent one, with any older unhandled
+exceptions attached as additional.
+
 You can cause built-ins to automatically throw exceptions on failure using
 
     use fatal;
 
-The C<fail> function responds to the caller's C<use fatal> state.  It
-either returns an unthrown exception, or throws the exception.
+The C<fail> function responds to the caller's C<use fatal> state.
+It either returns an unthrown exception, or throws the exception.
+Before you get too happy about this pragma, note that Perl 6 contains
+various parallel processing primitives that will tend to get blown
+up prematurely by thrown exceptions.  Unthrown exceptions are meant
+to provide a failsoft mechanism in which failures can be treated
+as data and dealt with one by one, without aborting executation
+of what may be perfectly valid parallel computations.  If you
+I<don't> deal with the failures as data, then the block exit
+semantics will eventually trigger a thrown exception.
 
+In any case, the overriding design principle here is that no
+unhandled exception is ever dropped on the floor, but propagated
+onward through subsequent C<$!> variables until it is handled.  If
+that never happens, the implicit outermost exception handler will
+eventually decide to abort and print all unhandled exceptions found
+in the C<$!> that it is responsible for.
+
 =head1 Closure traits
 
 A C<CATCH> block is just a trait of the closure containing it.  Other

Reply via email to