Initialising a dictionary with duplicate keys


#1

Is this expected behaviour (on v0.5. Haven’t tested v0.6)? It seems like it should at least throw a warning.

julia> Dict(:x=>1, :x=>2)
Dict{Symbol, Int} with 1 entry:
  :x => 2


#2

I would say this is expected behaviour since it expands to

dict = Dict{Symbol, Int}()
for (k, v) in (:x=>1, :x=>2)
  dict[k] = v
end

#3

If you, for some reason, want to have dictionary with duplicate keys you can use Base.ImmutableDict (which is however a bit tricky to use):

julia> a = Base.ImmutableDict(Base.ImmutableDict(Pair(:x, 1)), Pair(:x, 2))
Base.ImmutableDict{Symbol,Int64} with 2 entries:
  :x => 2
  :x => 1

Note that adding a new value with the same key will override the initial definition, so

julia> a[:x]
2

Way to construct multi-key ImmutableDict
#4

I can speak from experience with Clojure that throwing an exception can be a cause of confusion, especially when you mix literals and variables in map/set construction. For example:

julia> foo = :greeting
:greeting

julia> bar = :greeting
:greeting

julia> Dict(foo => "Hello, world!", bar => "Goodnight, moon!")
Dict{Symbol,String} with 1 entry:
  :greeting => "Goodnight, moon!"

The compromise Clojure has reached is that literal constructors (e.g. {key value, :foo 3}) throw exceptions if duplicate keys are provided, but the function constructors (e.g. (hash-map key value :foo 3) silently overwrite duplicate keys (similar to Julia’s Dict(...)). As a result, it is recommended to use Clojure’s literal constructors ({}) only with literals, and to use the function constructors ((hash-map ...)) if any variables will be used. Of course, this sort of implicit difference in functionality tends to cause confusion, especially for beginners, as one typically learns the literal constructor starting out, and the function constructor only after they’ve been bitten by an unintended duplicate key exception/bug.

For my money, I prefer Julia’s “only-one-way” approach, and I think it is much simpler for the constructors to be safe and require manual checks if one wants to raise on a duplicate key, than the reverse.