In Apocalypse 4, Larry Wall wrote:
|
|   In fact, a C<CATCH> of the form:
|
|       CATCH {
|           when xxx { ... }          # 1st case
|           when yyy { ... }          # 2nd case
|           ...                       # other cases, maybe a default
|       }
|
|    means something vaguely like:
|
|       BEGIN {
|           %MY.catcher = {
|               given current_exception() -> $! {
|
|                   when xxx { ... }  # 1st case from above
|                   when yyy { ... }  # 2nd case from above
|                   ...               # other cases, maybe a default
|
|                   die;            # rethrow $! as implicit default
|               }
|               $!.markclean;       # handled cleanly, in theory
|           }
|       }

Beautiful. The synthesis of CATCH, BEGIN blocks, %MY, given, when,
break, dwim =~, die, $!, $!.clean, and $!.stack is awe-inspiring.
The way proto-exceptions, fail, and use fatal work together is also
brilliant.

I particularly enjoyed this one:

       CATCH { when @$! =~ Foo { ... } }

I do have a few questions.

   1. Does this example:

      {
          my $p = P.new;   LAST { $p and $p.Done; }
          foo();
          my $q = Q.new;   LAST { $q and $q.Done; }
          ...
      }

      effectively get compiled into something like:

      {
          my $p;  my $q;
          $p = P.new;   LAST { $p and $p.Done; }
          foo();
          $q = Q.new;   LAST { $q and $q.Done; }
          ...
      }

      If not, how can we evaluate $q in the LAST block if foo() dies?
      Or are LASTs not handled by a magic BEGIN mechanism? Or are the
      LASTs converted into a BEGIN plus some run-time state variable
      that is only set when the LAST is encountered during execution?
      Or am I missing the point entirely ;-?

   2. Consider the following example:

      for my $file ( @files ) {
          my $f is last { close } = open $file or next;
          foo($f);
          CATCH { default { print "foo($f) failed\n" } }
          }

      The last and CATCH blocks must be invoked at the end of each
      time around the for block, no? Or should I be writing:

      for my $file ( @files ) {
          try {
              my $f is last { close } = open $file or next;
              foo($f);
              CATCH { default { print "foo($f) failed\n" } }
              }
          }

   3. Would the following execute the C<die>? When do I have to worry
      about "accidentally" catching control exceptions?

      sub ...
      {
          return if 1;
          fragile();
          CATCH { default { die "Couldn't fragile." } }
          }

   4. The test for "block exited successfully" is C< !$! || $!.clean >,
      for the purposes of the block-end handing code, correct?  So

          KEEP is like LAST { if ( !$! || $!.clean ) { ... } }
      and
          UNDO is like LAST { unless ( !$! || $!.clean ) { ... } }

      in which case CATCH is actually like UNDO with an implied given,
      die, and $!.markclean, except it's handled in a different end-
      block order, yes?

   5. What is the order of processing all these special blocks at the
      end of their containing block? Is it:

          1. CONTINUE
          2. CATCH
          3. KEEP
          4. UNDO
          5. LAST
          6. POST

      or some other fixed order, or is there some sort of order-of-
      encounter interleaving of some of the kinds of blocks?

   6. What is the value of

          my $x = try { "1" CATCH { default { "2" } } LAST { "3" } };

      What happens for each permutation of replacing "n" by die "n"?

   7. Is there any particular reason why multiple CATCH blocks can't
      simply be queued in some fashion like multiple LAST blocks?

Yours, &c, Tony Olekshy


Reply via email to