Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CONTROL phasers from a trait

Is it possible to add a CONTROL phaser from a trait?

Following the example from the docs, it's simple to add a custom control exception in runtime code:

class CX::Oops does X::Control {};
sub f { CONTROL { when CX::Oops { note 'Oops!'; .resume}}
        CX::Oops.new.throw;  }

f; # OUTPUT: «Oops»

However, my attempts to do so from a trait haven't worked:

sub trait_mod:<is>(Sub $fn, :$oopsable) {
    $fn.add_phaser: 'CONTROL', { when CX::Oops { note 'Oops!'; .resume} }}

sub g is oopsable { CX::Oops.new.throw; }
g; # OUTPUT: «control exception without handler»

From the .has_phasers and fire_phasers (fun name!) methods, I can tell that this is adding the control phaser. Do I need to do something to register it as a handler, or is there something else I'm missing?

like image 661
codesections Avatar asked May 23 '21 19:05

codesections


Video Answer


1 Answers

It's an interesting question whether CATCH and CONTROL really are phasers. They fit insofar as they use capital letters and that they react to something that happens at a certain time. However, they are also parsed in a different part of the grammar, as statement controls, and so are restricted to occurring at statement level. And the compiler doesn't handle them with a call to add_phasers, either. An exception handler implies some code generation, and it is the generated code in the body of the routine that actually results in the exception being handled.

One could reasonably ask if the compiler should not look to see if a trait did call add_phasers with CATCH or CONTROL and then generate code accordingly. However, since in the current compiler implementation the handlers are part of the routine body, and all work (except optimization) is completed on the routine body before trait handlers are called, it's simply too late for the trait to have an effect.

Additionally, the body of a CATCH and CONTROL block is not compiled simply as an ordinary block, but also gets code generated to handle the when smartmatching, and to rethrow the exception if none of the handlers match; at least this final step would need to be done manually. There's also something about updating $!, if I remember correctly.

The one bit of good news is that the forthcoming rakuast-based compiler frontend will:

  1. Provide an API to the AST of the routine in the trait handler. This can then be used to add the CATCH/CONTROL handler at AST level, and thus will get all of the correct semantics and perform the same as one written literally into the code.
  2. Delay the code generation until much later, so that the timing works out too.
like image 190
Jonathan Worthington Avatar answered Oct 17 '22 23:10

Jonathan Worthington