Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
The ordering operators (perl.org)
33 points by Amorymeltzer on April 9, 2022 | hide | past | favorite | 20 comments


Can you use <=> on arrays in Perl? In ruby that would be [$maj, $min, $rel] <=> [3, 6, 8]


At least in Perl 5 (which TFA uses), you can not. Or certainly not expect a useful result.

https://perldoc.perl.org/perlop#Relational-Operators


It says a numerical comparison, so it will compare only the length of the arrays.


<=> has some of the semantics of Fortran's "arithmetic" IF statement.

This can be useful, as the Fine Article shows, in sorts and searches, I've rolled it by hand a few times for tests like "is this offset in the line we're examining".


<=> and cmp also have the benefit that fewer comparisons are done. It might not be that big a deal for Perl scalars, but for C++, an overloaded operator< that does something like this:

   return left.a != right.a ? left.a < right.a
                            : left.b < right.b;
That might result in exponential number of compare operations if those nested comparisons are also overloaded, whereas with <=> (as of C++20), the number of compare operations can be made to be linear:

   return left.a <=> right.a < 0 || left.b <=> right.b < 0;


Sorry, that should have been:

    return !(left.a <=> right.a >= 0 && left.b <=> right.b >= 0);


For comparison, in Next Generation Shell, the above would be solved as follows:

    version_ok = version.split(".").map(Int) >= [3, 6, 8]


NGS looks interesting as a Bash alternative.

https://github.com/ngs-lang/ngs


Thank you!

For scripting, it is significantly better than bash (at least for most of the cases that I have).

The interactive part is not implemented yet but it is planned to be quite different from the dominant decades old approach. The plan is at https://github.com/ngs-lang/ngs/wiki/UI-Design


Interesting, why is there a separate operator for strings?

Are there scenarios when either operator (cmp or <=>) works, but they have different behaviour?


Perl doesn't have a way to say "this value is a number" or "this value is a string".

Instead, the two are effectively the same type (which Perl calls a scalar value), and you use different operators to treat them like strings or numbers as desired.

So, for example, you can do something like this:

    # declare $a and initialize it with a literal
    # numerical value of 3. 
    my $a = 3;

    # switch gears and treat it like a string
    # instead of a number by appending an "X".
    $a .= "X";

    # output a line that says "3X".
    print "$a\n";
Or like this:

    # declare $b and initialize it with a literal
    # string value of "l33t".
    my $b = "l33t";

    # do a regex substitution (string operation)
    # to remove letters. New string will be "33".
    $b =~ s/[a-z]//g;

    # multiply string "33" times 3.
    $b *= (1 + 1 + 1);

    # output a line that says "99".
    print "$b\n";
So, if you have an array of scalar values like "123" and "5", Perl doesn't know whether to sort these as numbers (5 goes first) or as strings ("123" goes first) because the value isn't necessarily a string or a number.


> Perl doesn't have a way to say "this value is a number" or "this value is a string".

This isn't really any different than JavaScript or similar languages that perform automatic type coercion. Internally scalars are differentiated. When writing Perl XS (the C extension interface), scalars are clearly differentiated into integers, doubles, strings, references (Perl's equivalent of pointers), and several other internal types. In a sense, a Perl scalar is the same as a "scalar" in many other languages (whether strongly or weakly, statically or dynamically typed), where you have two basic types--scalar and compound types. In C an integer, floating point, and pointer are all scalar values, as distinguished from an array, struct, or union.

So when you do `my $a = 3;`, `$a` at that point is definitely an integer type. However, it can be coerced (both conceptually and literally--in Perl objects are mutable and can have both their value and type changed in-place) into a string according to Perl's extremely complex DWIM type coercion rules.


>This isn't really any different than JavaScript or similar languages that perform automatic type coercion.

"1" + "1" is "11" in JavaScript. In Perl, it's 2. There's also no JS-like `typeof` operator in Perl. The types you mention in Perl XS are just an implementation detail from the perspective of the language itself. "1" and 1 are exactly the same value, not different values that can be coerced into each other.


> Perl doesn't have a way to say "this value is a number" or "this value is a string".

use Scalar::Util qw(looks_like_number);

#example

if(looks_like_number($value)) { say "$value is a number"; }


But looks_like_number("42") is still true.

OTOH, JSON::PP can tell the difference between string and number:

  $ perl -MJSON::PP -E 'say JSON::PP::encode_json(42);'
  42

  $ perl -MJSON::PP -E 'say JSON::PP::encode_json("42");'
  "42"


Isn't it that this is specifically JSON syntax?

"JSON recognises JSON".


No.


  my @chips = ("74HC08","8085AH","555","7C199-15");
  use_value($_) foreach @chips;
555 is a number; "555" is not a number.


Yes, when you compare numbers lexically, "cmp" will say that 2 sorts after 10, and "<=>" will say it sorts before:

  perl -e 'printf "%d %d\n", 2 <=> 10, 2 cmp 10'
prints

  -1 1


> Are there scenarios when either operator (cmp or <=>) works, but they have different behaviour?

It being Perl, you can basically throw anything at either operator if you like. It's trivial to find examples where the answers are different:

     perl -wlE 'say "a" <=> "b"; say "a" cmp "b";'
    Argument "b" isn't numeric in numeric comparison (<=>) at -e line 1.
    Argument "a" isn't numeric in numeric comparison (<=>) at -e line 1.
    0
    -1




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: