DEV Community

Cover image for Not So Obvious Semantic Changes (Part 3 of 3)
Elizabeth Mattijsen
Elizabeth Mattijsen

Posted on • Edited on

Not So Obvious Semantic Changes (Part 3 of 3)

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

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

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

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

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

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

Which is similar to:

# Perl
say STDERR $frobnicated;
Enter fullscreen mode Exit fullscreen mode

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

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

Whereas in Raku, everything between curly braces is an expression, so:

# Raku
%hash{a} = 42;
# bareword "a" interpreted as a call to subroutine "a"
Enter fullscreen mode Exit fullscreen mode

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

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

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

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)

Collapse
 
thibaultduponchelle profile image
Tib • Edited

@lizmat thank you you made my day(s) with this serie 👍