CATCH and throw in custom exception

CATCH must be in same block.

Problem in the first example is that no E but another exceptions is thrown. Try

class E is Exception { method message() { "Just stop already!" } };

CATCH {
    when E {
        .resume;
    }
    default { say .perl }
}

E.new.throw;

you could change when block

class E is Exception { method message() { "Just stop already!" } };

CATCH {
    when E {
        say .message;
    }
}

E.new.throw;

or definition of the class E, e.g.

class E is Exception { 
    has $.resume; 
    method message() { "Just stop already!" } 
};

CATCH {
    when E {
        say .resume;
    }
}

E.new(resume => 'stop here').throw;

It's an already filed .resume bug.


The error message isn't the most awesome P6 has ever produced but it isn't technically LTA because it is descriptive and related to the error (caused by the bug).


CATCH and throw in custom exception

I think it's just a .resume bug rather than being about custom exceptions.

Should 'CATCH' be called strictly after 'throw'?

No, that's not the issue. (That said, putting it after the .throw just so happens to avoid this bug; I'll return to that later.)


In the code that goes boom, you throw an exception, then .resume in response to it. Per the doc .resume:

Resumes control flow where .throw left it

Which in this case means where the arrow points:

E.new.throw ;
           

Now, consider this program:

42;

If you run that program you'll see:

Useless use of constant integer 42 in sink context (line 1)

That's because P6 applies "sink context" rules when deciding what to do at the end of a statement. Applying sink context entails calling .sink on the value produced by the statement. And for 42 the .sink method generates the "useless" warning.

But what's the value of a .resumed thrown exception?

class E is Exception {}
CATCH { when E { .resume } }
say E.new.throw.^name; # BOOTException
E.new.throw.sink;      # Cannot find method 'sink': no method cache and no .^find_method

It turns out it's a BOOTException object which isn't a high level P6 object but instead a low level VM object, one that doesn't have a .sink method (and also stymies P6's fallback methods for finding a method, hence the "I tried everything" error message).


So why does putting the CATCH block after the throw make a difference?

It seems the bug only occurs if the throw statement is the last statement. This works fine, just displaying 42:

class E is Exception {}
CATCH { when E { .resume } }
E.new.throw;
say 42;

As you presumably know, P6 treats the last statement of a block specially. Perhaps this bug is related to that.

Tags:

Raku