DataStructures.jl
DataStructures.jl copied to clipboard
Handle alternative types as default in DefaultDict
This is different than #530, which is asking about handling missing as a key. This issue relates to enabling missing as the default value.
This works and returns 42.0:
dd_real = DefaultDict(42.0,Dict(i => i for i in 1:3))
dd_real[0]
But this errors:
dd_missing = DefaultDict(missing,Dict(i => i for i in 1:3))
dd_missing[0]
MethodError: Cannot `convert` an object of type Missing to an object of type Int64
Testing just a bit more, it seems like dd_real works because 42.0 can be coerced into an Int. The issue related to having a default type that is not the same type.
This does not work:
dd_string = DefaultDict("abc",Dict(i => i for i in 1:3))
dd_string[0]
And errors with:
MethodError: Cannot `convert` an object of type String to an object of type Int64
Looks like the change that would be needed would be to modify
getindex(d::DefaultDictBase, key) = get!(d.d, key, d.default)
to
getindex(d::DefaultDictBase, key) = get(d.d, key, d.default)
in here: https://github.com/JuliaCollections/DataStructures.jl/blob/3b66dbcb802b5257e5a1667d50bc13d8b01f8ac7/src/default_dict.jl#L69
Tracing this back to Base - because this line calls get!, (I think) base doesn't want to allow a default return value that is different than the values stored in the Dict with get! since it could mutate the dict. Base allows mixed types when calling just get.
Is there a reason to use get! instead of get in default_dict.jl?
I could submit pull request if that little change above sounds reasonable.
Example of what I mean:
This errors:
d = Dict(i => i for i in 1:3)
get!(d,10,"abc")
While this does not:
d = Dict(i => i for i in 1:3)
get(d,10,"abc")
indeed, I have just made that PR.
If I had known you were going to offer I would have waited. It would be good if you could review it.
The following does work:
julia> dd_missing_u = DefaultDict(missing, Dict{Int, Union{Int,Missing}}(i => i for i in 1:3))
DefaultDict{Int64,Union{Missing, Int64},Missing} with 3 entries:
2 => 2
3 => 3
1 => 1
julia> dd_missing_u[0]
missing
Not sure if that is enough for your needs.
I would like it if:
DefaultDict{Int, Union{Missing,Int}}(missing, Dict(i => i for i in 1:3))
worked, but it doesn't (right now)
DefaultDict{Int, Union{Missing,Int}}(missing, Dict(i => i for i in 1:3))
now works (merged in https://github.com/JuliaCollections/DataStructures.jl/pull/730)
Reading through the discussion in https://github.com/JuliaCollections/DataStructures.jl/pull/576 I think we shouldn't change to get().