-->

Where should I catch a Perl 6 warning control exce

2019-06-18 03:02发布

问题:

I'm playing around with Perl 6's control exceptions. A warn raises a control exception which is invisible to normal exception control flow, and that exception resumes itself. That's kinda cool.

So, playing around with this, I wrote this to see what would happen. I'm not trying to solve a particular problem other than seeing what Perl 6 actually does:

use v6;

try {
    CONTROL {
        put "Caught an exception, in the try";
        put .^name;
        }
    do-that-thing-you-do();
    }

sub do-that-thing-you-do {
    CONTROL {
        put "Caught an exception, in the sub";
        put .^name;
        }
    warn "This is a warning";
    }

It looks like both fire:

Caught an exception, in the sub
CX::Warn
Caught an exception, in the try
CX::Warn
This is a warning
  in sub do-that-thing-you-do at resume.p6 line 16
MoarVM panic: Trying to unwind over wrong handler

Notice there's a Moar panic, which I've raise an issue for. But, I'm not really asking about that.

I'm curious about the picture of the flow here. I expected that a CONTROL in the sub would catch the exception and resume, so it wouldn't percolate up to the try. How should that flow?

Also, notice the exception is CX::Warn. I don't think I've done something odd there, but the Perl 6 types don't even list X::Warn

回答1:

To get the same behavior as the default warnings handler, then it's necessary to both catch the exception (as with CATCH, a CONTROL without smart-matching will re-throw) and also to resume after it.

CONTROL {
    when CX::Warn {
        say "Warning: $_";
        .resume
    }
}

sub foo() {
    say 1;
    warn 'oh gosh...';
    say 2;               # Not reached without .resume
}
foo();

There are many other control exceptions, and so it is wise to only match on CX::Warn rather than use default. Otherwise, take, next, last, emit, done (and, in 6.d, probably also await) could be netted by your handler, which would surely make for quite some headaches.