Home > Raku > Indicating absence

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.

Categories: Raku