DEV Community

Cover image for Cases of UPPER
Elizabeth Mattijsen
Elizabeth Mattijsen

Posted on

Cases of UPPER

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";
Enter fullscreen mode Exit fullscreen mode

will display:

before
after
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

Another way to create constant values at compile time, is to use the constant directive. For instance my 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 use statement 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);
}
Enter fullscreen mode Exit fullscreen mode

Which would show:

This is documentation
Enter fullscreen mode Exit fullscreen mode

Which is actually how the --doc command 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;
Enter fullscreen mode Exit fullscreen mode

Which is actually what the -c command 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;
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

will show:

second
first
Enter fullscreen mode Exit fullscreen mode

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)