Matching nothing
I requested and foolishly offered help with a Discord log bot to lizmat. While doing so I stumbled upon a neat use for none()
.
sub discord-log-stream(Mu:D :$channels is copy = %*ENV<DISCORD-CHANNELS> // none()) {
$channels = $channels.split('#', :skip-empty).any;
# ...
start react {
whenever $discord.messages -> $message {
next unless $channels ~~ $message.channel.name;
$result.emit: [ ‚#‘ ~ $message.channel.name, $message.author.&{ .username ~ ‚#‘ ~ .discriminator }, $message.content ];
}
}
}
If no channel list is given, the bot shall log all channels. Instead of special casing, I use an empty none
-Junction as a default value. With channels to include, $channel
contains an any
-Junction of Str
. Matching a single Str
with ~~
will return True
if the string is also in the any
-Junction. Any test against none()
will return True
. So my default value will always test True
. This is a little bit like matching against the inverse of the empty set.
As it happens none()
is quite resilient. It survives both .split
and .any
. Being an instance of Junction
makes it defined. That is helpful because it allows the :D
-type smiley and as such guards against undefined values.
Given that none()
is everything I would not wonder if one who masters Raku goes straight to निर्वाण.
Update:
Since none()
is anything but obvious, adding a constant with a speaking name adds clarity.
constant all-channels := none();
sub discord-log-stream(Mu:D :$channels is copy = %*ENV<DISCORD-CHANNELS> // all-channels) {
# ...
}
-
June 22, 2021 at 13:532021.25 Small Steps – Rakudo Weekly News