The Raku Programming Language contains more than 70 syntax elements that are completely in UPPERCASE. Why are they in uppercase? Because they indicate "Something Very Strange" going on (hence the allcaps).
These syntax elements provide quite a few ways of modifying the behaviour of code execution, and interfaces to classes and objects.
This series of blog posts intends to provide an overview of these syntax elements (which can loosely be grouped into "Phasers", "Methods", "Macros", "Pragmas" and "Dynamic Variables"), and how they can be used to your benefit.
Why not read the documentation? Well, in some cases there is ample documentation. For instance in the case of phasers. But in other cases the documentation is less clear. Especially if it is about when to use a given feature to provide a certain capability to your code.
Nonetheless it may be a good idea to start with (maybe yet another) overview of phasers, their flavours and how you can use them. Just to get a bit of a feel for it!
Phasers, by execution stage
In the Raku Programming Language there are basically two stages of execution (that matter for you as a developer): "compile time" and "runtime".
The compile time stage takes care of parsing the Raku code into an AST (which is short for Abstract Syntax Tree). When the compilation is complete, then that AST is converted into bytecode.
And the runtime stage is when that bytecode is actually being executed by the virtual machine (in case of Rakudo, that is most commonly MoarVM).
In practice this distinction is a lot more vague because quite a large part of the Rakudo implementation is actually written in Raku itself.
Compile time
When a Raku program is being compiled, it is also possible to actually execute code during this compilation. One of the ways to do that, is with the BEGIN phaser.
BEGIN
As with most phasers, the BEGIN phaser can either take a Block ({ ... }) or a so-called thunk.
A "thunk" is a piece of code that has no scope of its own (and thus shares it scope with the surrounding scope).
say "after";
BEGIN say "before";
will display:
before
after
because the say "before" is executed at compile time, and the say "after" at runtime. Even though you might think otherwise when you look at the order in which they occur in the code.
Note that these says occurred in "thunk"s because of the lack of { } indicating a scope. If you have multiple lines of code you need to execute at compile time, you can do that in such a scope:
BEGIN {
my $now = DateTime.now;
say $now;
}
The above will show when the code is being compiled.
The BEGIN phaser also returns the last value seen in it. And you can store that in a variable that will be set at compile time:
my $compiled-at = BEGIN DateTime.now;
say "This code was compiled at: $compiled-at";
Another way to create constant values at compile time, is to use the
constantdirective. For instancemy constant $answer = 42. The thunk on the right-hand side of the=is evaluated at compile time.
So what makes more sense to use? The BEGIN phaser, or the constant directive? For a part that depends on your coding style, and another part on the complexity of the code that you want to execute at compile time. And sometimes you use them side-by-side.
Note that the
usestatement also may execute code at compile time if the module used has not been pre-compiled yet, or has pre-compilation disabled.
Finally: the BEGIN phaser is special in that it is executed the moment it has been compiled. Almost all other phasers keep a queue of code to be executed at a given time.
CHECK
The CHECK phaser gets executed once the entire source code has been compiled into an AST. It comes both in Block and thunk flavours.
In the next language level of Raku, this will allow you to actually modify the AST before it is being turned into bytecode. But we're not there yet.
You could for instance use the CHECK phaser to show the documentation of the code in question:
=begin pod
This is documentation
=end pod
CHECK {
use Pod::To::Text;
say pod2text($=pod);
}
Which would show:
This is documentation
Which is actually how the
--doccommand line argument works.
Otherwise it is of little use currently. One could for instance use it to prevent actual execution, but only if the code was being compiled (which may not be the case if a module was already pre-compiled).
CHECK exit;
Which is actually what the
-ccommand line argument does.
If you really want to always prevent execution of your program or module depending on the phase of the moon, you can use the INIT phaser:
INIT exit if $phase-of-the-moon;
More on the INIT phaser in the next episode!
In any case, CHECK phasers are executed in the reverse order they are specified:
CHECK say "first";
CHECK say "second";
will show:
second
first
Conclusion
There are more than 70 language elements in the Raku Programming Language that consist of only UPPERCASE characters. They are written in uppercase because they are intended to stand out in code, because they indicate "Something Very Strange" going on.
The BEGIN and CHECK phaser apply to the compilation stage of a Raku program.
This concludes the first episode of cases of UPPER language elements in the Raku Programming Language. Stay tuned for more!
Top comments (0)