Subject: | all, any, none, notall: suggested prototype change to better match builtin 'map' |
'none' and friends have a prototype to behave like perl's builtin 'map'. This means that you can say
% perl -wE 'use List::MoreUtils qw(none); say none { say "hi" } 2, 3'
and have the first argument recognized as an anonymous sub, without needing the 'sub' keyword. (Obviously printing 'hi' is not a useful filter, I just have it for an example.) This is similar to
% perl -wE 'say map { say "hi" } 2, 3'
There is no comma between the end of the filter block and the next argument. Suppose the programmer makes a mistake and puts a comma in. With map, the error is obvious:
% perl -wE 'say map { say "hi" }, 2, 3'
syntax error at -e line 1, near "},"
But with none, the effect is to change the precedence, so that only the first element in the list becomes an argument to none, with the rest going to say:
% perl -wE 'use List::MoreUtils qw(none); say none { say "hi" }, 2, 3'
123
This is unfortunate - it would be much better for the misplaced comma to give an error as with map.
But I believe there is a solution. I think the current prototype is none(&@), is that right? If so, you can see the same problem with a pure-Perl implementation:
% perl -wE 'sub none(&@) { my $f = shift; local $_; foreach (@_) { return 0 if &$f } return 1 } say none { say "hi" }, 2, 3'
123
Changing the prototype to none(&$@) gives a compile-time error as desired:
% perl -wE 'sub none(&$@) { my $f = shift; local $_; foreach (@_) { return 0 if &$f } return 1 } say none { $_ eq "a" }, 2, 3'
Not enough arguments for main::none at -e line 1, near "},"
Doesn't that mean that none can no longer be called on an empty list? Luckily it doesn't. An explicit empty list is still fine:
% perl -wE 'sub none(&$@) { my $f = shift; local $_; foreach (@_) { return 0 if &$f } return 1 } say none { $_ eq "a" } ()'
1
The only existing code affected would be code which has a hardcoded call to none with a code block and nothing afterwards - or, perhaps, code which has the comma mistake above. In both cases, explicit parens can be used if for some reason you really want the rather pointless call of none on no elements.
Could you change the prototype of all, any, none, and notall from (&@) to (&$@) to get the improved diagnostic and consistent behaviour with map?