Sort using reference to subroutine name?

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on

I have function which I'd like to call telling it how to sort some
arrays.
I'd like to do something like:

my \$sort_by_x_ref = sub { return (\$x <=> \$x)};
my \$sort_by_y_ref = sub { return (\$y <=> \$y)}

sub print_sorted {
my \$sort_function = \$_[0]->();
print "Sorted \$_[1]\n";
foreach (sort keys %some_array) {
:
print...
:
}

&print_sorted ( \$sort_by_x_ref, "by X");
&print_sorted ( \$sort_by_y_ref, "by Y" );

That does not work. , and just \$sort_function do not
seem to work either.

Can this be done? What is the syntax?

My workaround is boring:

sub print_sorted {
print "Sorted \$_[1]\n";
foreach (sort {(\$_[0]) ? \$x <=> \$x : \$y <=> \$y } keys
%some_array) {
:
print...
:
}
&print_sorted ( 1, "by X");
&print_sorted ( 0, "by Y" );

Hein.

Re: Sort using reference to subroutine name?

Why are you doing this? (What did you think it would do for you?) I'm
fairly sure you just want

my \$sort_function = \$_[0];

here.

foreach (sort \$sort_function keys %some_array) {

except %some_array isn't an array, it's a hash. Using a block
will attempt to sort with a sub that returns
\$sort_function every time, which is unlikely to be successful.

Note that the sort function will need to be compiled into the package
that is current when 'sort' is called (or you could use the
(\$\$)-prototyped variant, but that's both slow and obscure) as otherwise
\$a and \$b won't work.

I'm not quite sure why you're doing this: why not just pass a ref to the
hash to sort by, and then use something like

my \$sort_by = \$_[0];

sort { \$sort_by-> <=> \$sort_by } ...;

?

Don't call subs with & unless you know what it does, and what it does is
what you want (hint: it probably isn't).

Ben

--
For the last month, a large number of PSNs in the Arpa[Inter-]net have been
reporting symptoms of congestion ... These reports have been accompanied by an
increasing number of user complaints ... As of June,... the Arpanet contained
47 nodes and 63 links. [ftp://rtfm.mit.edu/pub/arpaprob.txt ] * ben@morrow.me.uk

Re: Sort using reference to subroutine name?

:

I tried that first, but it didn't work for me.
So I check some pod pages and googles around to find that suggestion
in:
http://www.perlmonks.org/index.pl?node_id=3D680130

Right, sorry for the sloppy names. It was a hash.

Yeah, that is probably critical, but I'm not sure I entirely undestand
that.
I had tried putting a debug "print qq(in sort \$a \$b\n)" withing the
function indeed showed undefs for \$a and \$b :-(

That sounds like my problem.

Because I was thinking of various other sort funtions, not just
varying by hash.

Right, I get that, and have used similar contructs before.

I more or less know that, but got carried away in trying almost random
solutions for my sort challenge, as reasoned (flawed reasoning :-)
solutions did not work.

Thanks for the quick feedback!
Hein.

Re: Sort using reference to subroutine name?

Hmm, there's some *seriously* bad advice on that page :). I think what
you're not understanding is that \$_[0]->() calls the function once,
before you even start sorting: that's not what you want to do. You want
to call the function *during* the sort, for each comparison, so you need
to pass the actual function into sort somehow, not its return value.

If you call sort with a block, like

sort { STATEMENTS } LIST;

then the STATEMENTS are compiled into a new anonymous sub. It's almost
exactly the same as

my \$sub = sub { STATEMENTS };
sort \$sub LIST;

or even

sub sort_sub { STATEMENTS }
sort sort_sub LIST;

except that sort blocks are very slightly more efficient than ordinary

my \$sub = sub { STATEMENTS };
sort { \$sub } LIST;

is then trying to sort using a sub which returns the same subref for
every comparison: \$sub is never even called, so your carefully
constructed comparison subs become useless :). You could write a sort
block that explicitly calls the sub:

my \$sub = sub { STATEMENTS };
sort { \$sub->() } LIST;

but that's really just a waste of time: if all your sort sub is going to
do is call another function, you might as well pass that function to
sort directly.

No, it doesn't. I was talking about the case where you have

package Foo;

my \$sub = sub { \$a <=> \$b };

package Bar;

my @list = sort \$sub 2, 3, 1;

in which case sort is setting \$Bar::a and \$Bar::b, while the sub is
looking at \$Foo::a and \$Foo::b, so no useful comparisons get done (but
for a different reason from before). This would only be a problem if you
were passing in sort subs from a different package, which your example
code wasn't doing.

OK, that makes sense.

When you're lost, randomly trying things is *very* rarely helpful.
Re-reading the docs, adding 'warn' statements so you can see what is
actually going on, and (eventually) posting to Usenet are much more
likely to produce useful results :).

Ben

--
Raise your hand if you're invulnerable.
[ben@morrow.me.uk]