dictionary - Strange Dict behavior with keys of a custom type -


i have recursive function utilizes global dict store values obtained when traversing tree. however, @ least of values stored in dict seem disappear! simplified code shows problem:

type id     level::int32     x::int32 end  vdict = dict{id,float64}()  function getv(w::id)     if haskey(vdict,w)         return vdict[w]     end      if w.level == 12         return 1.0     end     w.x == -111 && println("dont have: ",w)      local vv = 0.0     j = -15:15         local wj = id(w.level+1,w.x+j)         vv += getv(wj)     end     vdict[w] = vv     w.x == -111 && println("just stored: ",w)     vv end  getv(id(0,0)) 

the output has many lines this:

just stored: id(11,-111) dont have: id(11,-111) stored: id(11,-111) dont have: id(11,-111) stored: id(11,-111) dont have: id(11,-111) ... 

do have silly error, or there bug in julia's dict?

by default, custom types come implementations of equality , hashing by object identity. since id type mutable, julia conservative , assumes care distinguishing each instance (since potentially diverge):

julia> type id # there's strong convention capitalize type names in julia            level::int32            x::int32        end  julia> x = id(11, -111)        y = id(11, -111)        x == y false  julia> x.level = 12; (x,y) (id(12,-111),id(11,-111)) 

julia doesn't know whether care object's long-term behavior or current value.

there 2 ways make behave you'd like:

  1. make custom type immutable. looks don't need mutate contents of id. simplest , straightforward way solve define immutable id. id(11, -111) indistinguishable other construction of id(11, -111) since values can never change. bonus, may see better performance, too.

  2. if need mutate values, alternatively define own implementations of == , base.hash care current value:

    ==(a::id, b::id) = a.level == b.level && a.x == b.x base.hash(a::id, h::uint) = hash(a.level, hash(a.x, h)) 

    as @stefankarpinski just pointed out on mailing list, isn't default mutable values "since makes easy stick in dict, mutate it, , 'lose it'." is, object's hash value has changed dictionary stored in place based upon old hash value, , can no longer access key/value pair key lookup. if create second object same original properties first won't able find since dictionary checks equality after finding hash match. way lookup key mutate original value or explicitly asking dictionary base.rehash! contents.

in case, highly recommend option 1.


Comments