April 2022 Archives

The ordering operators

Perl has two operators, cmp and <=>, which are basically never seen outside of sort blocks.

That doesn’t mean you can’t use them elsewhere, though. Certainly sort and these operators were designed to work seamlessly together but there isn’t anything sort-specific about the operators per se, and in some contexts they can be the most appropriate solution.

An example would be some code that used to go (almost exactly) like this:

my ( $maj, $min, $rel ) = split /[.]/, $version;
my $version_ok = $maj > 3 || (
    $maj == 3 && ($min > 6 || (
        $min == 6 && $rel >= 8
    ))
);

Basically, this is a check that the version number of something with a three-component dotted version is at least 3.6.8. As expressed in the code, for both the major and minor version there are two cases where they might be accepted: if the component is above a given threshold then the whole version is acceptable with no further questions, but if equal to that threshold, the version might still be acceptable depending on the value(s) of the lesser component(s). At the same time, if the value is below that threshold, the version is unacceptable, no further questions necessary. So there are three cases, two of which can succeed, and two of which require no further checks.

This is exactly what the <=> operator offers: if you ask $maj <=> 3 you will get 1 if the major version is above 3 (immediate success), -1 if it is below 3 (immediate failure), and 0 if it is equal to 3 (success to be determined from the lesser components). Because 0 is false, you can chain such comparisons with logical-or, until one of them gives an immediate success/fail – as of course we are used to doing in sort blocks.

And so this is what the code looks like now:

my ( $maj, $min, $rel ) = split /[.]/, $version;
my $version_ok = ( $maj <=> 3 || $min <=> 6 || $rel <=> 8 ) != -1;

The expression in parentheses has each component of the actual version on the left and the respective component of version 3.6.8 on the right, and will stop at the first comparison that gives a definite answer. The final != -1 then checks that the answer was not “the right side is greater” at the final comparison – i.e. “the given version is not below version 3.6.8”.

About Aristotle

user-pic Waxing philosophical