Why is `sort List::Util::uniq(BAR, BAZ);` different from `sort &List::Util::uniq(BAR, BAZ);`

95 Views Asked by At

I know & disables prototypes on but doesn't parentheses also do that. How are These two blocks of code different, and is there a reason that the top can NOT act like the bottom,

use List::Util;
use constant FOO => (1,2,3);
use constant BAR => (2,3,4,5,6);
use constant FOOBAR => sort List::Util::uniq(FOO, BAR);
use List::Util;
use constant FOO => (1,2,3);
use constant BAR => (2,3,4,5,6);
use constant FOOBAR => sort &List::Util::uniq(FOO, BAR);
2

There are 2 best solutions below

2
choroba On

sort is very special.

Warning: syntactical care is required when sorting the list returned from a function. If you want to sort the list returned by the function call "find_records(@key)", you can use:

           my @contact = sort { $a cmp $b } find_records @key;
           my @contact = sort +find_records(@key);
           my @contact = sort &find_records(@key);
           my @contact = sort(find_records(@key));

If instead you want to sort the array @key with the comparison routine "find_records()" then you can use:

           my @contact = sort { find_records() } @key;
           my @contact = sort find_records(@key);
           my @contact = sort(find_records @key);
           my @contact = sort(find_records (@key));
2
ikegami On

Because of the heuristics involved in guessing which of sort's calling convention you are using.


sort has a complicated syntax, with three fundamental calling conventions:[1]

sort LIST
sort BLOCK LIST
sort SUBNAME LIST

These alternative calling conventions introduce numerous ambiguities, including these:

  • sort { could be the start for sort BLOCK LIST or sort LIST.[2]
  • sort foo could be the start for sort SUBNAME LIST or sort LIST.[2]

As a result, the parser must often "guess". The issue at hand is that you want sort List::Util::uniq(FOO, BAR) to be parsed as sort LIST, but the parser "guessed" you were using sort FUNCTION LIST.

Preceding the expression with & prevents it from being treated as a SUBNAME, but it also overrides any prototype the sub might have. The following are alternative workarounds without that drawback:

sort( List::Util::uniq(FOO, BAR) )
sort +List::Util::uniq(FOO, BAR)
sort { $a cmp $b } List::Util::uniq(FOO, BAR)

  1. This is a simplification, since it doesn't factor in parens.
  2. LIST just means a generic expression evaluated in list context. Expressions can start with { or an identifier.