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

Hello Perl Monks

This is my first question here, so please don't laugh.

Can anyone explain to me what's going on in this code?

#!/usr/bin/perl use strict; use warnings; sub foo ($) { my $x = shift; print "foo gets '$x'\n"; return ($x+2, 33); } my @a = foo(42); print "a=@a\n"; @a = sort(foo(42)); print "a=@a\n"; @a = (sort foo(42)); print "a=@a\n"; @a = sort foo(42); print "a=@a\n";
which produces the following output on my Linux system with Perl 5.10.1:
foo gets '42' a=44 33 foo gets '42' a=33 44 a=42 a=42

If I use old-style subs (i.e. &foo instead of foo), then it produces 'a=33 44' three times, which is what I'd expect.

Replies are listed 'Best First'.
Re: New-style sub strangeness
by Corion (Patriarch) on Jun 07, 2011 at 15:42 UTC

    When you look at the output you get, you'll notice that sort foo(42) never calls foo. This is because Perl sees it as:

    > perl -MO=Deparse -e "sub foo($); sort foo(42);" sort foo 42

    ... which means "sort the list with a single element '42' by using foo as the comparison operator".

    If you use the "perl4" method of calling the subroutine (via &foo(...)), Perl knows what you really mean, but you could also tell this to Perl by adding a comma after the sort invocation, to tell sort that it gets a parameter list instead of a sort block:

    > perl -MO=Deparse -e "sub foo($){44,33}; print for sort( foo(42), );" sub foo ($) { 44, 33; } ; print $_ foreach (sort foo(42)); > perl -wle "sub foo($){44,33}; print for sort( foo(42), );" 33 44
      Aha! The penny drops with regard to following 'sort' by the name of a subroutine. Thank you for all three answers. I didn't know about -MO=Deparse -- that could be very useful.

      cheers, Chris

Re: New-style sub strangeness
by choroba (Cardinal) on Jun 07, 2011 at 15:38 UTC
    I'd expect it four times when using &foo, and I also get it. B::Deparse to help you understand:
    perl -MO=Deparse -e 'use strict; use warnings; sub foo ($) { my $x = shift; print "foo gets '$x'\n"; return ($x+2, 33); } my @a = foo(42); print "a=@a\n"; @a = sort(foo(42)); print "a=@a\n"; @a = (sort foo(42)); print "a=@a\n"; @a = sort foo(42); print "a=@a\n"; ' sub foo ($) { use warnings; use strict 'refs'; my $x = shift @_; print "foo gets \n"; return $x + 2, 33; } use warnings; use strict 'refs'; my(@a) = foo(42); print "a=@a\n"; @a = sort(foo(42)); print "a=@a\n"; @a = (sort foo 42); print "a=@a\n"; @a = (sort foo 42); print "a=@a\n"; -e syntax OK
    In other words, sort foo(42) is understood as "sort the list containing 42 by sorting function foo".
Re: New-style sub strangeness
by wind (Priest) on Jun 07, 2011 at 15:40 UTC
    Just read sort. It allows you to use a subroutine to set an alternative sorting method.
    sub numerical { $a <=> $b } @a = sort numerical (4,33); print "a = @a\n";