> 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
When you specify the types of the numbers used, so that you are testing the transitivity of a single instance of Eq, you will find that transitivity does hold in this case.
a :: Double
a = 2^53
b :: Double
b = 2.0^53
c :: Double
c = 2^53 + 1
main :: IO ()
main = do
print $ a == b -- True
print $ b == c -- True
print $ a == c -- True
This sort of distinction exists in other languages though: Java has == and equals. OCaml has = and == etc. (Not that Perl doesn't have its issues; but this is very low in that list imho)
Please note that Perl 6 has been renamed to Raku (https://raku.org using the #rakulang tag on social media). So in Perl `say "same" if .1 + .2 == .3` will not say anything, as that condition is not true. In Raku, `say "same" if .1 + .2 == .3` will display "same".
<=> 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:
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:
When it's that kind of comparison, that's an argument for putting the constant on the left. Then you'll know you're getting the kind of equality method defined for the constant (which is more typically what you want).
Common Lisp and related languages have = as a function: it is a numeric comparison. Like under equalp, (= 1 1.0) yields true. You might think it's superfluous to equalp, but has some virtues of its own, like supporting variadic arguments (= 1 1 1 1) and rejecting non-numeric arguments.
eq is often the wrong one to use: two instances of the same number can fail to be eq.
Lisp, the second oldest language after Fortran, didn't make this mistake. In Lisp, "=" isn't an operator at all. Assignment is (setf x y) and comparison is (eq x y) [and several variants of eq].
Common Lisp does this. EQL means reference-equals, and EQUAL means value-equals (recursive). If you need to custom behavior, then EQUALP is a generic function that can be overridden for your data types.
...and then it keeps going. EQ differs from EQL only by having undefined behavior on integers and characters, because that gives implementations the freedom to box those datatypes or not while still guaranteeing that EQ is always a pointer-comparison. And = is numeric equality, which is different than value equality because 0.0 is = to -0.0 but not EQL to it.
"He hadn’t quite internalized left-hand side vs. right-hand side." This is noteworthy.
In mathematics, equality is symmetric (a=b is the same as b=a).
In programming, variable assignment is asymmetric (a=b is not the same as b=a).
Some programming languages recognize this but get the change wrong by changing the equality operator to == or === and always preferring assignment to be =. Some get it right, e.g., := as assignment.
Actually `=` sort-of only does one thing. It asks the left argument what it wants to do with the values.
my @a = 1,2,3;
is almost the same as
my @a;
@a.VAR.STORE((1,2,3));
---
As for separate positional and associative access:
Raku has separate positional and named arguments to functions.
An argument list is actually a singular thing called a Capture. Even if it usually pretends to not be.
my \capture = \( 'a', b => 10 ); # Capture litteral
say capture[0]; # a
say capture{'b'}; # 10
sub foo ( |capture ) {
say capture[0]; # a
say capture{'b'}; # 10
}
foo |capture; # give it the above capture litteral
# foo 'a', b => 10
sub bar ( $a, :$b ){
say $a; # a (positional)
say $b; # 10 (named)
}
bar |capture; # give it the above capture litteral
# bar 'a', b => 10
To be able to easily extract out those parts, it helps if there is a different way to get at each.
The same thing also applies to extracting information out of regexes
'a10' ~~ / (.) # $0
$<b> = (..) # $<b>
/;
say $0; # a
say $<b>; # 10
say $/[0]; # a (positional index into $/)
say $/{'b'}; # 10 (named index into $/)
"=" is still equality. It's not an operator that compares two values. It's an operator that defines the left hand to be equal to the right hand. I feel like "=" for assignment is fine. For boolean comparison something like "=?" seems most clear, like asking a question whether the left and right hand side are equal.
"==" returns true if the left argument is numerically equal to the right argument.
"eq" returns true if the left argument is stringwise equal to the right argument.
see 'perldoc perlop' under the heading "Equality Operators"
reply