问题
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.
来源:https://stackoverflow.com/questions/43243412/where-should-i-catch-a-perl-6-warning-control-exception