Indicating absence
I can’t do any smartassing on Stackoverflow because I’m incompatible with the license they use there. That wont stop me from reading questions uzlxxxx did ask. In his last gainage of knowledge he sought to use Nil
to indicate the absence of a value at the end of a linked list. Nil is an old friend of this blog and it took me a good while to getting to like it.
Nil does indeed indicate the absence of a value. Indication is quite an active word and one can ask the question who is indicating to whom. I believe Nil is indicating the absence of a value to the compiler.
my $var = "value";
$var = Nil;
dd $var;
# Any $var = Any
To the debugger (That is you and me, the Debugger doesn’t remove any bugs. We do.) the absence is indicated by Any. As jnthn pointed out in the case of a Node in a linked list a type object associated to that list makes more sense. That’s not what Rakudo is doing.
my constant IterationEnd = nqp::create(Mu);
# eqv to Mu.new;
It’s using an instant of Mu
which introduces some problems.
my $var = Mu.new;
say [$var.Bool, $var.defined];
# OUTPUT: [True True]
Requesting an element beyond the end of a list should not be True nor defined. We could help that by mixin a role in.
my \Last = Mu.new but role {
method defined { False };
method Bool { False }
};
say [.Bool, .defined, .^name] given $var;
# OUTPUT: [False False Mu]
That’s better. It will work with if
, with
and //
. But for debugging it’s not so nice. We don’t get a specific error message or any information where the undefined value came from. We can define a singleton with a better name.
constant \Last = class BeyondLast {
method defined { False };
method Bool { False }
}.new but role { method new { die 'Sigleton is better left alone' } };
say [Last.WHAT, Last.defined, Last.so, Last ~~ Last, Last === Last ];
# OUTPUT: [(BeyondLast+{<anon|1>}) False False True True]
Now we get something undefined, wrong and better named. If there is any runtime error we wont get a message telling us where it came from. There is a whole class of objects that are undefined and false. We can use an exception bottled up in a Failure
as a default value.
constant Last = Failure.new(X::ValueAfterLast.new);
say [Last ~~ Last, Last === Last];
# OUTPUT: [True True]
my $node is default(Last); # line 3
$node = 42;
$node = Nil;
say $node === Last;
say $node;
CATCH { default { say .^name, ': ', .gist } }
# OUTPUT: True
X::ValueAfterLast: Value after last element requested.
in block at /home/dex/tmp/tmp.raku line 3
Sadly is default
does not allow code object or we could get a stacktrace that points to where the Nil was assigned. If the Failure
object slips through we get at least a decent error message.
There are many way to indicate unusual values. However, none of them should end with the user of a module. We got Failure
for that.
-
July 13, 2020 at 16:062020.28 Bridges 7 – Rakudo Weekly News
-
July 20, 2020 at 21:592020.29 Election Time – Rakudo Weekly News