9

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.

What would be an example of when it could be used outside of a Perl sort?

This is a best practice question.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pistol
  • 326
  • 4
  • 9

3 Answers3

7

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);
}
P Shved
  • 96,026
  • 17
  • 121
  • 165
5

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;
}
daotoad
  • 26,689
  • 7
  • 59
  • 100
Michael Carman
  • 30,628
  • 10
  • 74
  • 122
  • 1
    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 Sep 03 '09 at 13:55
  • What's the performance benefit of delegating these two comparisions from explicitely written statements to preprocessor's internals? – P Shved Sep 03 '09 at 15:38
  • 1
    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 Sep 03 '09 at 17:26
2

In any sort of comparison method. For example, you could have a complicated object, but it 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 source code 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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ether
  • 53,118
  • 13
  • 86
  • 159
  • 2
    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 Sep 03 '09 at 03:14