Is there a way to overload how Base.Set
does its object comparisons in Julia?
I tried overloading isequal
and ==
, but my objects are still marked as different when they should be the same.
E.g.
type Test
x
y
end
function ==(a::Test, b::Test)
return a.x == b.x && a.y == b.y
end
Set([Test(2,3), Test(2,3)])
gives
Set([Test(2,3),Test(2,3)])
There is a useful package for composite type comparisons, AutoHashEquals:
using AutoHashEquals
@auto_hash_equals type Test
x
y
end
X = Test(2, 3)
Y = Test(2, 3)
Z = Test(1, 3)
X == Y # = true
X == Z # = false
Set([X, Y, Z]) # = Set([Test(2,3),Test(1,3)])
However, like @Gnimuc-K pointed out "this macro is only useful for mutable types when they are used as immutable records."
A Set
is a kind of Dict
with values of type Void
: ref
type Set{T} <: AbstractSet{T}
dict::Dict{T,Void}
Set() = new(Dict{T,Void}())
Set(itr) = union!(new(Dict{T,Void}()), itr)
end
And Julia-lang documentation describes Dic
type as follow:
Dict is the standard associative collection. Its implementation uses hash() as the hashing function for the key, and isequal() to determine equality. Define these two functions for custom types to override how they are stored in a hash table.
Check, dict.jl, and look for ht_keyindex2()
and ht_keyindex()
functions. Both will return an index
only if these two conditions are true
:
if !isslotmissing(h,index) && isequal(key,keys[index])
return index
end
Where in the above: index = hashindex(key, sz)
Julia uses hash()
function do the task of hashing:
hash(x[, h])
Compute an integer hash code such that isequal(x,y) implies hash(x)==hash(y). The optional second argument h is a hash code to be mixed with the result. New types should implement the 2-argument form, typically by calling the 2-argument hash method recursively in order to mix hashes of the contents with each other (and with h). Typically, any type that implements hash should also implement its own == (hence isequal) to guarantee the property mentioned above.
So with these preparations it is obvious that overriding Base.==
, is not the right & complete way to do the task, but
hash()
function to return the same hashindex
andBase.==
it is sufficient to override Base.isequal
Code:
type Test
x
y
end
Base.hash(a::Test, h::UInt) = hash(a.y, hash(a.x, hash(:Test, h)))
Base.isequal(a::Test, b::Test) = Base.isequal(hash(a), hash(b))
Set([Test(2,3), Test(2,3)])
The point is, although Test(2,3) == Test(2,3) #=> false
it works as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With