The other day, someone on a mailing list asked how to check several regexes on many strings. In that article I recommended the use of the all function of List::MoreUtils as a more compact way to write that code, but the question remained: Does it short-circuit?

Will that check all the values even if after checking two it already knows the answer?

We could of course read the source code of that module, but I found it more interesting to write a script that will allow us to see it in action.

The following script has two arrays, in @yes every value is true, in @not they are all true, except one of them: the number 0 is false.

At first we check two solutions, one of the is using grep to return the list of values that are true: grep { $_ } @array. Then we compare that with the original array using ==. This puts them in scalar context which means we are actually comparing the number of elements in the original array and the number of element grep returned. @array == grep { $_ } @array. We could have been more explicit with the scalar context writing: (scalar @array == scalar grep { $_ } @array

We print the result of the comparison.

In the second solution we just use the all function imported from List::MoreUtils: all { $_ } @array

use strict;
use warnings;
use 5.010;

use List::MoreUtils qw(all);

my @yes = (1, 2, 3, 4, 5);
my @not = (6, 7, 0, 8, 9);

say 'yes: ', (@yes == grep { $_ } @yes);   # yes: 1
say 'no:  ', (@not == grep { $_ } @not);   # no:

say 'all yes: ', all { $_ } @yes;          # all yes: 1
say 'all no:  ', all { $_ } @not;          # all no:

Next to each line I added the result. As you can see, they yes-lines printed 1 (the true value) and the no-lines printed only the text. They returned false.

Now let's add a print-statement (or rather a say-statement) to both solutions. We now have { say; $_ } in each expression. That is, in each block we have two statement. The first is say without any parameter. It will default to print the content of $_. The second statement is $_ itself that needs to be examined by grep and all.

This way, as grep and all iterate over the elements in the @yes and @not arrays, we will also see them printed. (I also added a separation line to make it easier to see what was printed from the "grep" and what from the "all".

use strict;
use warnings;
use 5.010;
use List::MoreUtils qw(all);

my @yes = (1, 2, 3, 4, 5);
my @not = (6, 7, 0, 8, 9);

say 'yes: ', (scalar @yes == scalar grep { say; $_ } @yes);
say 'no:  ', (scalar @not == scalar grep { say; $_ } @not);
say '----';

say 'all yes: ', all { say; $_ } @yes;
say 'all no:  ', all { say; $_ } @not;

The output:

1
2
3
4
5
yes: 1
6
7
0
8
9
no:
----
1
2
3
4
5
all yes: 1
6
7
0
all no:

Before the separation line all the numbers were printed. 1-5 from @yes and 6,7,0,8,9 from @not. Below the separation line all the number were printed from @yes, but in the @not array the printing has stopped after the first false value was found.

Conclusion

The all function imported from List::MoreUtils will only check the cases as long as they return true. If any of them returns false all will already know that it needs to return false and returns it immediately. This is especially important when there are lots of elements in the array to be checked and/or when each comparison is expensive.