Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Sorting result of function call

by Hofmator (Curate)
on Dec 20, 2006 at 09:29 UTC ( [id://590870]=perlquestion: print w/replies, xml ) Need Help??

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

I'm a bit surprised by the behaviour of the following code:
use strict; use warnings; my %h = (1=>2, 3=>4); sub say { print @_, $/ }; sub get_keys { print 'called:'; if (wantarray()) { print 'array:'; } else { print defined wantarray() ? 'scalar' : 'void'; } return keys %h; } # Output: say sort get_keys; # get_keys say sort get_keys(); # say sort &get_keys; # called:array:13 say sort &get_keys(); # called:array:13 say sort @{[get_keys]}; # called:array:13 say sort @{[get_keys()]}; # called:array:13

I would have expected that all these outputs would be identical. Here my guesses what went wrong. Could somebody shed some more light on it, please.

  • The first case somehow gets interpreted as a bareword - and use strict; doesn't complain because there is a subroutine with that name.
  • For the second case I'm really at a loss ...
  • The rest of the cases show various ways of making it work. I'm a bit surprised as perlsub says this concerning the calling of functions
    NAME(LIST); # & is optional with parentheses. NAME LIST; # Parentheses optional if predeclared/import +ed. &NAME(LIST); # Circumvent prototypes.
    Therefore there shouldn't be any difference between get_keys() and &get_keys() as get_keys doesn't use prototypes.

In case it matters: This is perl, v5.6.1 built for i386-linux.

And btw, I came across this when I tested App::Ack (Version 1.50) and tried to run ack --help types which doesn't display any types for me. Tracking it down, I reached the following line in App::Ack::show_help_types, which exhibits the behaviour of case 2 above.

for my $type ( sort( filetypes_supported() ) ) {

-- Hofmator

Code written by Hofmator and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Replies are listed 'Best First'.
Re: Sorting result of function call
by jbert (Priest) on Dec 20, 2006 at 09:45 UTC
    I don't know the details of what is going wrong, but I suspect that it is due to the attempts of sort to interpret it's first argument as a comparison sub or block.

    If you put in an explicit { $a cmp $b } in as the first parameter, all of your tests do the same thing - print "called:array:13".

    It's a bit ambiguous actually - should "sort subname" be interpreted as "using this sub as the sort comparison routine, sort the empty list" or "call this sub in list context and sort the results with the default sort comparator".

    The behaviour is surprising on the face of it, but I'm not (yet) sure it's wrong. Yet another reason to eschew prototypes (in this case, that of sort) I suppose.

      It's a bit ambiguous actually - should "sort subname" be interpreted as "using this sub as the sort comparison routine, sort the empty list" or "call this sub in list context and sort the results with the default sort comparator".

      Maybe I'm misunderstanding you here, but "sort subname" is my first testcase and it neither behaves as your first alternative nor as your second!

      -- Hofmator

      Code written by Hofmator and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

        Yes, I'd expect "sort subname" to mean "sort the empty list with the comparison func subname" - because "sort bareword LIST" means sort the (possibly empty) list with bareword as a comparison func.

        And I'd expect "sort subname()" to mean "invoke subname to get a list, to sort with the default comparator" - because I interpret "subname()" to always mean "invoke subname".

        So I'd expect your first two examples to have different behaviour (but not the behaviour we get).

        But I'm not sure my expectations are in line with "documented reality", so I'm loath to say there definitely is a bug.

        I'm hoping to learn something in this thread :-)

Re: Sorting result of function call
by sgt (Deacon) on Dec 20, 2006 at 10:25 UTC

    I can confirm the same result on cygwin with 5.8.7:

    % stephan@armen (/home/stephan) % % perl -w sort_context.px get_keys called:array:13 called:array:13 called:array:13 called:array:13

    deparse tells us:

    % stephan@armen (/home/stephan) % % perl -MO=Deparse sort_context.px use warnings; use strict 'refs'; my(%h) = (1, 2, 3, 4); sub say { print @_, $/; } sub get_keys { print 'called:'; if (wantarray) { print 'array:'; } else { print defined wantarray ? 'scalar' : 'void'; } return keys %h; } say sort('get_keys'); say((sort get_keys ())); say sort(&get_keys); say sort(&get_keys()); say sort(@{[get_keys()];}); say sort(@{[get_keys()];}); sort_context.px syntax OK
    so in the first case get_keys gets interpreted as a string. seems like a bug (an old one...) with use strict; (especially if one follows the principle of least surprise) still it's true that it is quite ambiguous... hth --stephan
      Thanks for trying that out. Deparse is a good idea, I get the same results as you except for case two, where my Deparse says
      say sort('get_keys' ());
      vs your
      say((sort get_keys ()));

      Interestingly, feeding my Deparse output back to perl leads to a syntax error. Your version seems to indicate what perl is doing here. Trying to sort the empty list () with the compare-function get_keys, hence the empty return.

      -- Hofmator

      Code written by Hofmator and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: Sorting result of function call
by kirbyk (Friar) on Dec 20, 2006 at 17:09 UTC
    That second one is a bit surprising, but when you look at perldoc -f sort:
    sort SUBNAME LIST
     
    sort BLOCK LIST
     
    sort LIST
    
    It sort of makes sense that 'sort get_stuff()' hits the first signature - it's sort, using the sorting rules in subname get_stuff, of an empty list.

    It's not exactly DWIM. But we humans get a lot of advantage from understanding that subroutine name. It's moderately likely that you'll pass an empty list into a sort in code, and it would be highly annoying if your sort routine was sometimes interpreted as a source of values depending on if your list was populated. So, I think this is good behavior - you have to be very explicit for it not to be considered the sort rules function.

    -- Kirby, IMDb.com

Re: Sorting result of function call
by petdance (Parson) on Dec 20, 2006 at 15:56 UTC
    Thanks for the heads-up. I split it into two statements just to bypass this mess.

    xoxo,
    Andy

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://590870]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (6)
As of 2024-03-28 12:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found