Experimental features
During Raku development, new features are often made available for
users as experimental before their design is completed. Eventually
these features may be made part of the Raku specification. To use these
features, one uses the experimental
pragma in program source code, for
example, like this:
use experimental :macros;
These are the features that, for the time being, are experimental.
pack|Language,pack
Pack is a feature that allows binary serialization of general data structures,
and is inherited from
Perl's pack.
The pack
order creates a Buf by packing data structures in a certain
way given by a packing string with the options shown
in the description of unpack. You turn it on by
inserting this pragma at the beginning of your program:
use experimental :pack;
For instance, we can pack numbers interpreting them as hexadecimal (H
) with
the pattern repeating until there are no more elements (*
):
use experimental :pack;
say pack("H*", "414243").contents;# OUTPUT: Ā«(65 66 67)ā¤Ā»
There is a corresponding unpack
routine that does exactly the opposite.
use experimental :pack;
my $buf=Buf.new(65,66,67);
say $buf.unpack("H*"); # OUTPUT: Ā«414243ā¤Ā»
Not all of the symbols above are guaranteed to be implemented, and the roadmap does not include a fixed date for getting out of that stage.
Please see also documentation for pack and unpack in the Blob page.
macros|Language,macros
Macros are code-generating routines, that generate code in compile time, before the program is executed. In Raku its use is still experimental and it needs to be turned on via the pragma
use experimental :macros;
Macro processing happens during parsing time. A macro generates an abstract
syntax tree, which is grafted into the program syntax tree. quasi
is the
routine that performs this task.
use experimental :macros;
macro does-nothing() {
quasi {}
};
does-nothing; # OUTPUT: Ā«Ā»
Macros are a kind of routine, so they can take arguments in exactly the same way, and act also in almost the same way.
use experimental :macros;
macro is-mighty( $who ) {
quasi { "$who is mighty!"}
};
say is-mighty "Freija"; # OUTPUT: Ā« "Freija" is mighty!ā¤Ā»
"Almost" accounts for the fact that the argument is inserted as a literal,
including the quotes. Please note that we can also eliminate the parentheses for
a macro call, following the same rules as a routine. You can use the unquoting
construct {{{}}}
to get rid of this kind of thing:
use experimental :macros;
macro is-mighty( $who ) {
quasi { {{{$who}}} ~ " is mighty!"}
};
say is-mighty "Freija"; # OUTPUT: Ā«Freija is mighty!ā¤Ā»
Since macro expansion happens at parse time, care must be taken when using external variables in them:
use experimental :macros;
my $called;
macro called() {
$called++;
quasi { "Called" }
};
say called() ~ " $called times";
say called() ~ " $called times"; # OUTPUT: Ā«Called 2 timesā¤Called 2 timesā¤Ā»
Since macros are expanded at parse time, $called
will be the result when runtime
starts, which is already 2
, as printed. Initializing $called
with 0,
however, will make this print Called 0 times
since that initialization is run
after the parse phase, when the macros are expanded.
Macros are terribly useful when complicated, computed initializations need to be done. However, they are still in the experimental nursery for a good reason. Although the features shown above are not very likely to change, anything, even their very presence, might change at any one time depending in necessities, so it would be best to keep them away from production code. Meanwhile, taking a look at this article by Masak as well as 007, a new macro language, might provide a glimpse into the things to come.
cached|Language,:cached
The following pragma:
use experimental :cached;
turns on the is cached
trait, which stores the result of a routine call,
returning the same value if called with the same arguments.
It can be used when heavy calculations are involved, as in this sample that uses amicable numbers, taken from the 2018 Advent Calendar:
use experimental :cached;
sub aliquot-parts( $number ) is cached {
(^$number).grep: $number %% *;
}
sub infix:<amic>( $m, $n ) {
$m == aliquot-parts($n).sum &&
$n == aliquot-parts($m).sum;
}
# Taken from https://en.wikipedia.org/wiki/Amicable_numbers
my @numbers = [2620, 2924, 5020, 5564, 6232, 6368, 66928, 66992];
say "Aliquot parts of $_ are ", aliquot-parts $_ for @numbers;
for @numbers X @numbers -> @pair {
say "@pair[0] and @pair[1] are ",
@pair[0] amic @pair[1]??" "!!"not ", "amicable";
}
This code caches the computation of the aliquot parts, so that when the
amic
operator is called, it's only computed once; as a matter of fact, the
first loop which prints these aliquot parts will be the only one that actually
perform the computation.
See also the description of the trait for additional information and examples.
Note: This feature is not thread-safe.
rakuast|Language,:rakuast
The pragma:
use experimental :rakuast;
makes the RakuAST package and its classes available for
use in language versions before 6.e
.