When is the spaceship operator used outside a sort?
Asked Answered
P

3

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.

Palatal answered 2/9, 2009 at 22:35 Comment(1)
@ether: Only the "operator" tag? I thought you liked creating new operator tags!Barrus
G
8

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);
}
Goat answered 2/9, 2009 at 23:9 Comment(0)
H
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;
}
Haversine answered 3/9, 2009 at 2:21 Comment(3)
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. :PHaversine
What's the performance benefit of delegating these two comparisions from explicitely written statements to preprocessor's internals?Goat
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.Haversine
D
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.

Declass answered 2/9, 2009 at 23:1 Comment(1)
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.Concordance

© 2022 - 2024 — McMap. All rights reserved.