IIFE alternatives in Raku

Viewed 113

In Ruby I can group together some lines of code like so with a begin block:

x = begin
  puts "Hi!"
  a = 2
  b = 3
  a + b
end

puts x # 5

it's immediately evaluated and its value is the last value of the block (a + b here) (Javascripters do a similar thing with IIFEs)

What are the ways to do this in Raku? Is there anything smoother than:

my $x = ({
  say "Hi!";
  my $a = 2;
  my $b = 3;
  $a + $b;
})();

say $x; # 5
2 Answers

Insert a do in front of the block. This tells Raku to:

  • Immediately do whatever follows the do on its right hand side;

  • Return the value to the do's left hand side:

my $x = do {
  put "Hi!";
  my $a = 2;
  my $b = 3;
  $a + $b;
}

That said, one rarely needs to use do.

Instead, there are many other IIFE forms in Raku that just work naturally without fuss. I'll mention just two because they're used extensively in Raku code:

with whatever { .foo } else { .bar }

You might think I'm being silly, but those are two IIFEs. They form lexical scopes, have parameter lists, bind from arguments, the works. Loads of Raku constructs work like that.

In the above case where I haven't written an explicit parameter list, this isn't obvious. The fact that .foo is called on whatever if whatever is defined, and .bar is called on it if it isn't, is both implicit and due to the particular IIFE calling behavior of with.

See also if, while, given, and many, many more.


What's going on becomes more obvious if you introduce an explicit parameter list with ->:

for whatever -> $a, $b { say $a + $b }

That iterates whatever, binding two consecutive elements from it to $a and $b, until whatever is empty. If it has an odd number of elements, one might write:

for whatever -> $a, $b? { say $a + $b }

And so on.


Bottom line: a huge number of occurrences of {...} in Raku are IIFEs, even if they don't look like it. But if they're immediately after an =, Raku defaults to assuming you want to assign the lambda rather than immediately executing it, so you need to insert a do in that particular case.

Welcome to Raku!

my $x = BEGIN {
    say "Hi!";
    my $a = 2;
    my $b = 3;
    $a + $b;
}

I guess the common ancestry of Raku and Ruby shows :-)

Also note that to create a constant, you can also use constant:

my constant $x = do {
    say "Hi!";
    my $a = 2;
    my $b = 3;
    $a + $b;
}

If you can have a single statement, you can leave off the braces:

my $x = BEGIN 2 + 3;

or:

my constant $x = 2 + 3;

Regarding blocks: if they are in sink context (similar to "void" context in some languages), then they will execute just like that:

{
    say "Executing block";
}

No need to explicitely call it: it will be called for you :-)

Related