DEV Community

Elizabeth Mattijsen
Elizabeth Mattijsen

Posted on • Edited on

That's the topic

This is part 3 of the "Don't fear the grepper!" series.

Setting the topic

In the first instalment, we saw that a subroutine could be reduced to a pointy block:

sub is-even($number) { $number %% 2 }
Enter fullscreen mode Exit fullscreen mode

And that could be simplified to:

-> $number { $number %% 2 }
Enter fullscreen mode Exit fullscreen mode

and after that, it got simplified to

* %% 2
Enter fullscreen mode Exit fullscreen mode

Now, this is all very cool, but it limits to what you can do in the condition. A more complex condition could not be specified that way. So maybe we need to look at simplification in another direction as well.

Another way to simplify the pointy block version is using the topic variable $_. So instead of:

-> $number { $number %% 2 }
Enter fullscreen mode Exit fullscreen mode

we could write:

-> $_ { $_ %% 2 }
Enter fullscreen mode Exit fullscreen mode

The topic variable $_ is an important tool to avoid repeating yourself. Like in any conversation, one does not need to repeat the topic over and over again. However, you might say, in the above example we did repeat $_! Well, in fact, you don't have to:

{ $_ %% 2 }
Enter fullscreen mode Exit fullscreen mode

is an even more simplified block (which may be familiar to some of you as a "lambda"). Any block with code in it, will automatically set the topic variable $_ inside of that block to the argument passed to it.

One could argue that it no longer looks like a pointy block, and you'd be right. But under the hood, it still acts as if -> $_ was specified, and thus preserves its "pointy" behaviour.

Note that you can call still call that block as if it were a subroutine:

say { $_ %% 2 }(137); # False
say { $_ %% 2 }(42);  # True
Enter fullscreen mode Exit fullscreen mode

More on the topic

You don't need to define the $_ variable yourself: it is automatically defined in any scope, so you can assign to it whenever you want to.

$_ = 42;
say $_; # 42
Enter fullscreen mode Exit fullscreen mode

To make this clearer in code, there is actually a given control construct that will set $_ inside the scope it defines:

given 42 {
    say $_; # 42
}
Enter fullscreen mode Exit fullscreen mode

Every scope has its own topic, its own $_ variable. You could think of it like every scope has a my $_ in it. Fortunately, you don't have to specify that, so you don't have to repeat yourself!

Here's an example of multiple scopes and topics:

$_ = 666;
given 42 {
    say $_; # 42
}
say $_; # 666
Enter fullscreen mode Exit fullscreen mode

Note that the $_ after the given block retained the value it had before the given block. That's because the (implicit) outer block also had its own $_ defined in it. No need to worry about stepping on each others toes!

The invisible invocant

Like many things in the Raku Programming Language, there is also a method version of say. So you could write the above code as:

given 42 {
    $_.say; # 42
}
Enter fullscreen mode Exit fullscreen mode

One of the superpowers of the topic variable is that it is also the default for the invocant in method calls. This means that if the invocant of a method call is the topic, then you don't need to specify it. This allows you to write the previous example as:

given 42 {
    .say; # 42
}
Enter fullscreen mode Exit fullscreen mode

No invocant specified: the topic is assumed.

Using the topic in grep

So let's expand the logic inside the block of a grep. In this example, we have a list of words, and we want to filter out the ones that are completely written in uppercase:

say <dog BIRD Cat COW>.grep({ $_ eq .uc }); # (BIRD COW)
Enter fullscreen mode Exit fullscreen mode

Inside the block, we're converting whatever was given as argument to uppercase (.uc) and then comparing that as a string (eq) with what was given as argument ($_). The result is that you get just the words that were already all uppercase to begin with.

Note the syntax for creating a list of words, using < ... >. This is called "word quoting" in Raku, and is really handy for specifying a list of words, separated by whitespace.

Conclusion

This concludes the third part of the series, this time introducing the topic variable $_, how it is always defined in every scope, and how it can be used as an invisible invocant to methods. And on the fly, also got introduced to the < ... > word quoting feature.

Questions and comments are always welcome. You can also drop into the #raku-beginner channel on Libera.chat, or on Discord if you'd like to have more immediate feedback.

I hope you liked it! Thanks again for reading all the way to the end.

Top comments (0)