Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if a list is empty (Raku)

Tags:

raku

FAQ: In Raku how to check if a list is empty ? Are there more idiomatic ways than:

my @l = ();
say @l.elems == 0;
say @l == ();
say @l.Bool;

The doc on list recommends smartmatching

say $l ~~ ();
  1. Do you know other ways ?
  2. Can you explain why () === () is wrong even if "" === "" is right: I'm not clear on that.
like image 997
Tinmarino Avatar asked Mar 25 '20 22:03

Tinmarino


1 Answers

Of those suggested:

say @l.elems == 0;

This is a good one to avoid, because it forces evaluation of all elements in a lazy list (which may lead to an exception if there are iterators marked as lazy, since the alternative would be running until all memory is exhausted).

say @l == ();

This works, but has the same problem as above. The == operator is numeric equality, and so it will coerce both sides to a number and then compare them. That also boils down to @l.elems (via. @l.Numeric). You could write this form cheaper as @l == 0, which is the neatest way if you really do want to ask for how many elements there are in total.

say @l.Bool;

This is better, because in a lazy list it only forces evaluation of one element at most to answer the question. However, it's actually the inverse of what was asked: this is True if the array is not empty. It's more natural to use the ? and ! prefix operators like this:

say ?@l; # is not empty
say !@l; # is empty

Though often you don't even need to do that, because things like if and unless provide a boolean context. Thus one could write:

if @l { }        # not empty
unless @l { }    # empty

These are probably the best ways.

As to other suggestions:

say $l ~~ ();

This is fine, though probably slower than the boolification approach.

() === () is wrong even if "" === "" is right

That's because List is a reference type, not a value type. Since () constructs a distinct empty list each time, they are distinct objects, and so will compare as non-identical. You can use eqv instead:

say () eqv ()    # True

But don't use this to check if a list is empty, because it's probably overly specific. For example:

my @l; say @l eqv ();    # False
my @l; say @l eqv [];    # True

This is because () is of type List, while my @l declares an Array. In general, you don't want to care what type is really there.

Finally, about this line:

my @l = ();

The assignment of () is pointless; my @a already creates an empty Array. In fact, it's a common enough code smell that Comma IDE gives a weak warning about this:

Warning

like image 55
Jonathan Worthington Avatar answered Oct 06 '22 18:10

Jonathan Worthington