w8lle has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!

I've noticed that my subroutine behaves differently depending on if I call it with an "&" character or not. I'm running the script on Ubuntu with Perl v5.26.1.

I have a list with duplicated entries and a subroutine that returns the unique entries from that list. If I assign the result of my subroutine to another list and then print that list, it doesn't matter if the subroutine is called with a preceding "&" character or not...

However, if I use the result of the subroutine directly in a for loop, the subroutine works fine if called with an "&" character but doesn't do it's job if it's absent!

Any thoughts; is this a feature or a fault??

#!/usr/bin/perl use strict; use warnings; my @list = qw (a a b b c c d d); print "\nAssigning list:\n"; for my $i (0 .. 1) { my @unique = ($i)? removeDuplicates (@list): &removeDuplicates +(@list); my $ampersand = ($i)? "": "&"; print $ampersand, $_, "\n" for (sort @unique); print "=\n"; } print "\nUsing in for loop:\n"; for my $i (0 .. 1) { if ($i) { for my $character (sort removeDuplicates (@list)) { print $character, "\n"; } } else { for my $character (sort &removeDuplicates (@list)) { print "&", $character, "\n"; } } print "=\n"; } sub removeDuplicates { my %hash; @hash{@_} = 1; return keys %hash; }

Running the above script gives me the following output:

user@host:~/scripts/test$ ./unique.pl Assigning list: &a &b &c &d = a b c d = Using in for loop: &a &b &c &d = a a b b c c d d = user@host:~/scripts/test$

Many thanks in advance!

Replies are listed 'Best First'.
Re: Ampersand changes behavior of subroutine
by hippo (Archbishop) on Feb 08, 2019 at 09:44 UTC

    As you are passing an explicit subroutine name to sort it takes that as the sorting operation. Remove the sort entirely (or don't pass it the subroutine name eg. by using the leading ampersand) and everything works fine.

    So, it's a feature - not a bug.

      Yes, that did the trick! :-)

      Thank you very much!

Re: Ampersand changes behavior of subroutine
by choroba (Cardinal) on Feb 08, 2019 at 13:32 UTC
    Documented in perldoc -f sort:
    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));
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Ampersand changes behavior of subroutine
by haukex (Archbishop) on Feb 08, 2019 at 19:47 UTC
    I've noticed that my subroutine behaves differently depending on if I call it with an "&" character or not.

    Although the others have already explained that in this case it's because of the way sort works, I just wanted to briefly address the more general question about calling subs with and without an ampersand: see this node for an explanation.