views:

281

answers:

3

This is a best practice question.

I've only seen the Perl spaceship operator (<=>) used in numeric sort routines. But it seems useful in other situations. I just can't think of a practical use.

Can anyone give me an example of when it could be used outside of a Perl sort?

+2  A: 

In any sort of comparison method. For example you could have a complicated object but still has a defined "order", so you could define a comparison function for it (which you don't have to use inside a sort method, although it would be handy):

package Foo;

# ... other stuff...

# Note: this is a class function, not a method
sub cmp
{
    my $object1 = shift;
    my $object2 = shift;

    my $compare1 = sprintf("%04d%04d%04d", $object1->{field1}, $object1->{field2}, $object1->{field3});
    my $compare2 = sprintf("%04d%04d%04d", $object2->{field1}, $object2->{field2}, $object2->{field3});
    return $compare1 <=> $compare2;
}

This is a totally contrived example of course. However, in my company's sourcecode I found nearly exactly the above, for comparing objects used for holding date and time information.

One other use I can think of is for statistical analysis -- if a value is repeatedly run against a list of values, you can tell if the value is higher or lower than the set's arithmetic median:

use List::Util qw(sum);
# $result will be
#   -1 if value is lower than the median of @setOfValues,
#    1 if value is higher than the median of @setOfValues,
#    0 if value is equal to the median
my $result = sum(map { $value <=> $_ } @setOfValues);

Here's one more, from wikipedia: "If the two arguments cannot be compared (e.g. one of them is NaN), the operator returns undef." i.e. you can determine if two numbers are a a number at once, although personally I'd go for the less cryptic Scalar::Util::looks_like_number.

Ether
Actually, the `undef` behavior can cause problems, because `undef` in a sort will cause Perl to most likely die. But we can make a numeric sort that handles NaN's: `sub numeric { $a <=> $b // ($a == $a) - ($b == $b) }` This will sort NaN's to the beginning, which has the positive effect of at least not dying.
Chris Lutz
+6  A: 

I'm writing a control system for robot Joe that wants to go to robot Mary and recharge her. They move along the integer points on the line. Joe starts at $j and can walk 1 meter in any direction per time unit. Mary stands still at $m and can't move -- she needs a good recharge! The controlling program would look like that:

while ($m != $j) {
    $j += ($m <=> $j);
}
Pavel Shved
+5  A: 

The <=> operator would be useful for a binary search algorithm. Most programing languages don't have an operator that does a three-way comparison which makes it necessary to do two comparisons per iteration. With <=> you can do just one.

sub binary_search {
    my $value = shift;
    my $array = shift;
    my $low   = 0;
    my $high  = $#$array;

    while ($low <= $high) {
        my $mid = $low + int(($high - $low) / 2);

        given ($array->[$mid] <=> $value) {
            when (-1) { $low  = $mid + 1 }
            when ( 1) { $high = $mid - 1 }
            when ( 0) { return $mid      }
        }
    }

    return;
}
Michael Carman
Given how surprisingly difficult it is to *correctly* implement a binary search, I can only hope that I haven't contributed yet another broken example to the world. :P
Michael Carman
What's the performance benefit of delegating these two comparisions from explicitely written statements to preprocessor's internals?
Pavel Shved
At the bytecode level there's one operator, not two: `perl -MO=Terse -e "$a <=> $b"` That said, since Perl is implemented in C (which doesn't have a three-way comparison operator) the `<=>` must be implemented as two comparisons by the internals. Any performance benefit would be that the expansion happens in C rather than Perl. Of course, ultimately the limit is what the processor's instruction set supports regardless of what operators C has.
Michael Carman