Raku and the MAIN arguments warn problem

A few days ago I upgraded one of my machines, and this involved the upgrade of Rakudo from an ancient version (2020-something) to a recent release.
So far so good, but my Simple Jekyll Stat generator stopped working!
Argh!

And that made me digging a little to find out what was wrong.

2022-04-21 UPDATE

After digging and searching for, I opened an issue against Rakudo.
It is worth reading the discussion and the test I’ve made, that prove that the behavior has changed during time and that this is fine since, it is documented. Even if I think it could be better documented!

The code

The code that generated the problem was like the following:

sub MAIN( Str :$dir
            where { .so && .IO.d // warn "Specify the directory [$dir]" } ) {
    say $dir;
}



The problematic code is the warn call within the where condition in the MAIN argument checking. The idea is to print a useful message when the argument $dir is set to a non directory, without having to deal with USAGE and friends.

The problem

When running with Rakudo 2022-03, I got something as follows:

% raku ~/tmp/test.p6 --dir=foo
Use of uninitialized value of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to
something meaningful.
 in block  at /home/luca/tmp/test.p6 line 4
Specify the directory []
 in block  at /home/luca/tmp/test.p6 line 4
Specify the directory [foo]
 in block  at /home/luca/tmp/test.p6 line 4
Use of uninitialized value of type Any in string context.
Methods .^name, .raku, .gist, or .say can be used to stringify it to
something meaningful.
 in block  at /home/luca/tmp/test.p6 line 4
Specify the directory []
 in block  at /home/luca/tmp/test.p6 line 4
Usage:
 /home/luca/tmp/test.p6 [--dir=<Str where { ... }>]


while when running with an ancient Rakudo (e.g., 2020-01), it worked as expected.
One interesting thing to note in the above output, is that the warn is called three times (or in general, multiple times), with only the second one with a valued $foo.
The fact that where can be called multiple times is specified in the documentation:

The code in where clauses has some limitations: anything that produces side-effects (e.g., printing output, pulling from an iterator, or increasing a state variable) is not supported and may produce surprising results if used. Also, the code of the where clause may run more than once for a single typecheck in some implementations.


The solution

Interestingly, the solution to the problem, that allows to run the same code with a recent Rakudo, is to explicitly indicate the variable to check in the where clause, therefore not using the topic:

sub MAIN( Str :$dir
            where { $dir.so && $dir.IO.d // warn "Specify the directory [$dir]" } ) {
    say $dir;
}



Conclusions

You shold always stay up-to-date, so that your application is battle-tested against current version of Raku and Rakudo.
Besides this trivial fact, sometimes Raku makes things difficult to understand, or better, Raku is great to understand what you want to do even when you don’t write it, but sometimes you need to be clearer!

The article Raku and the MAIN arguments warn problem has been posted by Luca Ferrari on April 12, 2022

Tags: raku