4

Is it possible to pass a block of code to a sub using "parentheses" syntax?

I.e. when i write

List::MoreUtils::any { defined ($_) } (undef, undef, 1);

it works. But when i try to add parentheses

List::MoreUtils::any ( { defined ($_) } , (undef, undef, 1) );

this is interpreted as an anonymous hash, giving an error message. Neither escaping nor using eval helps.

The idea behind all the fuss is if the call is a part of an expression, i.e.

if (first_index { defined (${$_})} $jms_positions > $jms_positionals_seen )

some operator following the arguments might be executed before the call, producing an undesired result.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152

3 Answers3

14

An anonymous subroutine is declared with the syntax

sub { say "The sub with no name!" };

Perl's prototype system allows a special exception where a code block is the first parameter, in which case you can leave off the leading sub and just pass the block, similar to a Perl builtin. But this only works when calling it in the parentheses-less style. Using parens causes the parser to think you want to pass a hash-ref.

So you can say

List::MoreUtils::any( sub { defined }, undef, undef, 1 );

If you insist on using parens.

friedo
  • 65,762
  • 16
  • 114
  • 184
  • Somehow, this works. I thought a `sub' required a return statement inside a block to yield anything to the calling party. Surprisingly, it doesn't! Perl's syntax is indeed the oddest one i've ever seen. – ivan_pozdeev Mar 07 '11 at 19:53
  • 1
    => the parens do not turn off the prototype. For that you would also need the `&` sigil. In this case, the parens just confuse perl's parser. – Eric Strom Mar 07 '11 at 22:21
  • @ivan_pozdeev => all blocks that are not loops return the last evaluated expression, so `sub {5}` and `sub {return 5}` are equivalent. As are `$x ? 2 : 3` and `do{if ($x) {2} else {3}}` – Eric Strom Mar 07 '11 at 22:26
5

No, only for the builtins.

$ perl -ce'map({ "..." } @a)'
-e syntax OK

$ perl -ce'grep({ "..." } @a)'
-e syntax OK

$ perl -ce'sub f(&@); f { "..." } @a'
-e syntax OK

$ perl -ce'sub f(&@); f({ "..." } @a)'
Array found where operator expected at -e line 1, near "} "
        (Missing operator before  ?)
syntax error at -e line 1, near "} @a"
-e had compilation errors.

Adding parens around the whole call is usually a suitable workaround.

( any { defined } (undef, undef, 1) )
ikegami
  • 367,544
  • 15
  • 269
  • 518
2

Just insert sub:

List::MoreUtils::any ( sub { defined ($_) } , (undef, undef, 1) );
reinierpost
  • 8,425
  • 1
  • 38
  • 70