I'm implementing a simple linked list and to denote the fact that there is no next node, I'm using the value Nil
. The thing is that when assigned to a container, Nil
will attempt to revert the container to its default value which means I need to use the container's default value or Any
to determine if the linked list's end has been reached. However, I'd still like to use Nil
(if only for its clear intent) and no other value to test for the non-existence of a next node in the code (e.g., until $current === Any
, last if $current-node === Any;
). For some context:
class Node {
has $.data is rw is required;
has $.next is rw = Nil;
}
class UnorderedList {
has $!head = Nil;
method add(\item --> Nil) {
my $temp = Node.new: data => item;
$temp.next = $!head;
$!head = $temp;
}
method size(--> UInt) {
my $current = $!head;
my UInt $count = 0;
until $current === Any { # <=== HERE
$count += 1;
$current .= next;
}
return $count;
}
method gist(--> Str) {
my $current-node = $!head;
my $items := gather loop {
last if $current-node === Any; # <=== HERE
take $current-node.data;
$current-node .= next;
}
$items.join(', ')
}
}
This is a bit like asking "how can I still have rain fall on my head while using an umbrella". :-) The primary reason Nil
exists in Raku is to provide a value that a function can return on a soft failure to produce a result, which will be safe if assigned into any container that supports being undefined (or defaulted).
Thus, one can write a function func
that can return Nil
, and it will Just Work for a caller my SomeType $foo = func()
or for a caller my OtherType $bar = func()
.
While there is the is default(Nil)
trick, I'd strongly suggest using some other value as your sentinel. Trying to use a language feature in a situation where you don't want the primary behavior it exists to provide will generally not go smoothly.
The Node
type object itself would be a reasonable choice. Thus this:
has $!head = Nil;
Becomes:
has Node $!head;
And the test becomes:
until $current === Node {
However, I'd probably write it as:
while $current.defined {
Which also supports subclassing of Node
. On the other hand, if I know Node
is an implementation detail of my class, I'd feel safe enough to use rely on the default boolification semantics to remove the clutter:
while $current {
Meanwhile, this:
last if $current-node === Any;
Could become:
last without $current-node;
Or for consistency if choosing the "rely on the boolification" approach:
last unless $current-node;
Finally, if Node
is just an implementation detail, I'd move it inside UnorderedList
and make it my
scoped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With