Reputation: 4901
I ran into an issue trying to using a dictionary whose keys are a tuple including a composite type.
Here is a minimal example to replicate my issue:
import Base: hash, isequal
type T
a :: Int
b :: Int
end
function isequal(A::(T,Int), B::(T,Int))
A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
hash(A[1].a + A[1].b + A[2])
end
d = Dict{(T,Int),Int}()
d[(T(1,1),1)] = 1
d[(T(2,2),2)] = 2
r = (T(2,2),2)
for k in keys(d)
println(isequal(r, k) && hash(r) == hash(k))
end
println(d[r])
Running this results in:
false
true
ERROR: key not found: (T(2,2),2)
So isequal
and hash
work, but for some reason the dict is not.
Does anyone know what is going on? Thank you.
Upvotes: 2
Views: 1642
Reputation: 11644
There is something I don't quite understand in this case about the types of tuples and dispatching, but basically you need to implement the two argument form of hash
for this case. The following very similar code works as expected, as a point of comparison, without the two argument form:
type T
a::Int
b::Int
end
function Base.isequal(A::T, B::T)
println("isequal", A, " ", B)
A.a == B.a && A.b == B.b
end
function Base.hash(A::T)
println("hash", A)
hash(A.a + A.b)
end
d = Dict{T,Int}()
d[T(1,1)] = 1
d[T(2,2)] = 2
println("test")
r = T(2,2)
println(d[r])
with output
isequalT(1,1) T(1,1)
hashT(1,1)
isequalT(2,2) T(2,2)
hashT(2,2)
test
hashT(2,2)
isequalT(2,2) T(2,2)
2
Upvotes: 1
Reputation: 4901
The problem can be solved by creating hash
& isequal
functions for each composite type rather than for the overall tuple.
If you key is (T,Int)
:
Instead of this:
function isequal(A::(T,Int), B::(T,Int))
A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
hash(A[1].a + A[1].b + A[2])
end
Do this:
function isequal(A::T, B::T)
A.a == B.a && A.b == B.b
end
function hash(A::T)
hash(A.a + A.b)
end
If you want the original formulation to work, you have to specify Base.hash with the optional second argument: h::Uint64
:
function isequal(A::(T,Int), B::(T,Int))
A[1].a == B[1].a && A[1].b == B[1].b && A[2] == B[2]
end
function hash(A::(T,Int))
hash(A[1].a + A[1].b + A[2])
end
function hash(A::(T,Int), h::Uint64)
hash(A[1].a + A[1].b + A[2] + h)
end
Upvotes: 0