raku's feed operator (pipelines)
09.11.2023 2 min readRecently, I’ve been writing a small program in Raku to help me case a sequence of words (kebab, snake, camel, etc.). This means testing a character for symbols, removing extra spaces, and various other operations. One of the functions ended up looking like this:
trim-extra-spaces(alphanumeric($s.lc)).split(" ").join("-");
I didn’t like this. Luckily for us, raku
has the ==>
feed operator, which seems to be similar to Elixir’s |>
pipe operator. Refactored, it looks like this.
alphanumeric($s.lc)
==> trim-extra-spaces()
==> split(" ")
==> join("-")
However, I quickly ran into a problem:
sub my-func($s) {
return alphanumeric($s.lc)
==> trim-extra-spaces()
==> split(" ")
==> join("-");
}
my-func("she-sells seashells on the sea!shore").say; # "shesells seashells on the seashore"
Adding the return
was causing my tests to fail.
Although this looks like how we’d usually write a return statement, the code above won’t actually do what we’d expect! return
doesn’t return the result of the operation - it just returns the result of the first function (in this case, alphanumeric
). In Raku, we have naked returns, but if we really wanted to be explicit about this, we have a few options:
-
Implicit, naked return
-
Return at the end:
sub my-func($s) {
alphanumeric($s.lc)
==> trim-extra-spaces()
==> split(" ")
==> join("-")
==> return;
}
- Wrap the result of the operation in parentheses:
sub my-func($s) {
return (alphanumeric($s.lc)
==> trim-extra-spaces()
==> split(" ")
==> join("-"));
}
- Assign it to a variable first:
sub my-func($s) {
my $res = alphanumeric($s.lc)
==> trim-extra-spaces()
==> split(" ")
==> join("-");
return $res;
}
Personally, I’m not a fan of option 1, but that’s just me. Whatever option you do decide to go with, just be aware that returns work a little differently when you use the feed operator.