Open jtrakk opened 3 years ago
The best solution is probably to remove the fallback definition where ==
calls ===
. Then you unambiguously need to use ===
to check if two things are identical, whatever they might be, and ==
only when it has been explicitly defined and so "makes sense".
You can also use isapprox
, although perhaps there's no guaranteed it will fail:
julia> a ≈ b
ERROR: MethodError: no method matching isapprox(::Vector{Int64}, ::Int64)
I've made that change in a branch before, and in Core.Compiler.:(==), and found we may rely on the fallback definition sometimes more often than you might think. Perhaps those were often supposed to be isequal
calls or ===
, but it can be hard to be sure everyone has picked the right one.
Here's the old code for deprecating the ==
fallback: https://github.com/JuliaLang/julia/pull/16764/files#diff-12e7a6522633012a408b1bdee7639e8cb722617fe1a8ed6a3881bf4ad1ebdbbdR14
From forensics, it appears that what killed that change in particular is that we define in
to be the computation of ==
over the values in the iterator.
You can also use isapprox, although perhaps there's no guaranteed it will fail:
My package IsApprox does something like this. It encodes different notions of closeness in types. One of these types is Equal
.
julia> isapprox(Equal(), 1, 1)
true
julia> isapprox(Equal(), 1, 1 + 1e-15)
false
This is free to be given any symantics, and I think erroring when things can't be sensibly compared is best. But, it currently falls back to ==
, which falls back to ===
. I can't think of a way to exclude just this last fallback method.
==
only when it has been explicitly defined and so "makes sense".
Piggy-backing off of this, should the same be true for hash
? That currently falls back to objectid
as well, via hash(@nospecialize(x), h::UInt) = hash_uint(3h - objectid(x))
.
I do really think that it would have been better to make x == y
strict and error unless x
and y
have types that it makes sense to compare and require x === y
for the more general "are these the same object" comparison or isequal(x, y)
for the "are these hash-equal" comparison.
That is how it works inside Core.Compiler
==
, ===
, isequal
, isapprox
, ≈
, and the entirely unrelated =
are already a lot for new folks. Introducing a new ≐
which should typically be preferred over ==
that isn't called ==
for historical reasons seems fairly beginner unfriendly and equality is something beginners are going to have to work with. I support trying to change the behavior of ==
in 2.0 but not introducing another notion of equality in 1.x.
While we're at it I don't like this either.
julia> [1; 2; 3;;]
3×1 Matrix{Int64}:
1
2
3
julia> [1; 2; 3;;] ≈ [1,2,3]
true
I often make mistakes by using
==
between two objects that I shouldn't be comparing, such as comparing a number to an array of numbers or comparing a string to a character. The==
comparison evaluates tofalse
, but it wasn't the comparison I meant to make. For example,I wish there were an equality-checking operator that would give an error for incompatible types, like in the example above. I'm not sure if the right implementation would be
<:
subtyping relationshipconvert
into each other's typespromote
into a shared typeor something else, or multiple different operators for different purposes. There are plenty of equals-like operators in unicode (eg ≟, ≐). Regardless, the current situation where my mistakes result in silent
false
s causes me problems too often for comfort; I would much rather get an explicit error that I can correct.What would be a good solution here?