Raku / problem-solving

🦋 Problem Solving, a repo for handling problems that require review, deliberation and possibly debate
Artistic License 2.0
70 stars 16 forks source link

INIT blocks in module does not behave nicely #304

Open Skarsnik opened 2 years ago

Skarsnik commented 2 years ago

INIT block in an exported sub inside a module file is called even if the sub is called inside a BEGIN phaser. Note that this does not happen if the module and the caller code are in the same file.

Example Piko.rakumod. I added other phasers to see how they behave too. I stumble across this trying to forbid a sub to be run at compile time.

module Piko {
sub foo is export {
    say "Piko::foo";
    my $run-time;
    CHECK {say "CHECK : ", defined $run-time}
    BEGIN {say "BEGIN : ", defined $run-time}
    INIT { say "INIT  : ", defined $run-time; 
          $run-time = True; };
    ENTER {say "ENTER : ", defined $run-time}
    LEAVE {say "LEAVE : ", defined $run-time}
    say "Before the test for defined", defined $run-time;
    die "Compile time" unless defined $run-time;
    say $run-time;
}
}

If I use the module for example like that. (Note the BEGIN foo();)

[skarsnik@localhost perl6-gumbo]$ ../../rakudo-2021.09/install/bin/rakudo -I ~/rakudo/lib/ -I ./ -M Piko -e 'BEGIN foo();'
INIT  : False
ENTER : True
Piko::foo
Before the test for definedTrue
True
LEAVE : True
[skarsnik@localhost perl6-gumbo]$

We can see that the INIT phaser gets called. I am not very familiar with the precompilation process but it could probably be the correct behaviour too since we are in the running phase of the module when we do use Module? BEGIN and CHECK are only called at the module pre-comp phase (not sure if that is also correct?)

codesections commented 2 years ago

My (perhaps incorrect/incomplete) understanding is that this behavior is correct and is a consequence of the way Raku allows nesting of compile times and run times. (E.g., EVAL is a nested compile time inside the program's run time – which is why it can say that it's ===SORRY!===, indicating a compile-time error). So, even though the module is being executed inside the run time of your program, it has it's own nested compile and run times and triggers the corresponding phasers for each.

… or, at least, I think that's what's happening. The idea of nested compile times isn't currently well-documented, and I'm not 100% certain of the details.