No Return Context in Raku
In Perl, a subroutine can determine in what context it is being called by using the wantarray function. Available contexts are scalar, list and void:
# Perl
sub say_context {
say wantarray
? "list"
: defined(wantarray)
? "scalar"
: "void";
}
my $a = say_context(); # scalar
my @b = say_context(); # list
say_context(); # void
In Raku, there is no such thing a caller's context. A subroutine (well, technically any block) only ever returns a single value. Such a value may well be a List, or any other object.
So you can simulate returning multiple values in Raku:
# Raku
sub return-scalar() { 42 }
sub return-list() { 42,666 } # note the comma makes the list
my $a = return-scalar;
say $a; # 42
my ($b,$c) = return-list; # unpack list into variables
say $b; # 42
say $c; # 666
But you should realise that it is in fact a single List that is being returned by return-list, that will be unpacked into $b and $c.
Simulating void context is possible in a way in Raku, but it requires returning an object that has a specific sink method defined for it. And that goes beyond the scope of these blog posts.
Just Saying
In Perl, using the print command will stringify the given value and send this to standard output. The say command will add a newline after that.
In Raku, there are basically 3 methods with which an object can be stringified: Str, gist and raku. The Str method is supposed to return a complete stringification of the given expression. The gist method is intended to provide a gist of the stringification of the given expression. For small objects, this is usually the same as the Str method. For bigger objects, the gist method is at liberty to drop information, or to summarise it.
The raku method provides basically a built-in Data::Dumper: the method is supposed to return a string that can be evaluated to re-create the given object. This is of course not always 100% possible, but all effort should be taken to make it roundtrip.
So given these methods, how do these relate to outputting strings? Well, the print command in Raku basically works like the print command in Perl: it calls the Str method on the given expression and sends that to standard output.
The say command in Perl merely adds a newline to the stringification of the expression:
# Perl
say $frobnicated; # stringify and send to STDOUT with newline
In Raku, the say command first calls the gist method (rather than the Str method), and adds a newline.
# Raku
say $frobnicated; # call method .gist and send to STDOUT with newline
In Raku, if you want to have the standard stringification happen when outputting to standard output, you can either call the Str method on the expression explicitly, or you can prefix the expression with a ~, or you can use the put command:
# Raku
say $frobnicated.Str; # explicit standard stringification
say ~$frobnicated; # prefix ~ is same as .Str
put $frobnicated; # implicit standard stringification
Additionally, Raku has a note command, that functions the same as say, but will send the output to standard error:
# Raku
note $frobnicated; # call method .gist and send to STDERR with newline
Which is similar to:
# Perl
say STDERR $frobnicated;
except that method gist is called rather than the standard stringification.
The Rakudo implementation of the Raku Programming Language also includes a tiny Data::Dumper facility, so tiny it lost the t: dd. This basically calls the raku method on the given expression, and prints that, with possibly some extra information, on standard error:
# Raku
dd "foo"; # "foo"
dd 5+42i; # <5+42i>
dd now; # Instant.from-posix(1691224400.111166001)
dd Date.today; # Date.new(2023,8,5)
my Int $a = 42;
dd $a; # Int $a = 42
Note that this feature is purely intended to facilitate debugging, and should probably not be used in any code running in production.
Always Expression between Curlies
In Raku, something between curly braces ({ }) is always an expression, no matter where it occurs. This applies to indexing into a hash, where this differs in semantics from Perl:
# Perl
%hash{a} = 42;
# the bareword "a" interpreted as a string
Whereas in Raku, everything between curly braces is an expression, so:
# Raku
%hash{a} = 42;
# bareword "a" interpreted as a call to subroutine "a"
Fortunately, if that subroutine does not exist in that lexical scope, there will be a compilation error that will be very clear:
# Raku
%hash{a} = 42;
# ===SORRY!=== Error while compiling …
Undeclared routine: a
used at line …
For all other normal code uses (if, for, while, etc.), the curly braces act the same in Perl and Raku.
However in Raku, they can also be used inside double quoted strings:
# Raku
my $a = 42;
my $b = 666;
say "The sum of $a and $b is { $a + $b }";
# The sum of 42 and 666 is 708
Which is a lot more consistent and a lot less line-noisy than the equivalent in Perl using @{[ ]}:
# Perl
my $a = 42;
my $b = 666;
say "The sum of $a and $b is @{[ $a + $b ]}";
# The sum of 42 and 666 is 708
Summary
This blog post elaborated on the absence of context in Raku, the subtle semantic differences between say and friends, and the fact that the contents of curlies are always an expression in Raku.
Top comments (1)
@lizmat thank you you made my day(s) with this serie 👍