Hi!
Since I couldn’t find a tuple-based (immutable and ordered) dictionary I came up with the following:
struct TupleDict{K,V} <: AbstractDict{K,V}
ks::Tuple{Vararg{K}}
vs::Tuple{Vararg{V}}
function TupleDict{K,V}(ks::Tuple{Vararg{K}}, vs::Tuple{Vararg{V}}) where {K,V}
length(ks) == length(vs) || throw(ArgumentError("..."))
allunique(ks) || throw(ArgumentError("..."))
new{K,V}(ks, vs)
end
end
TupleDict{K,V}(ps::Pair...) where {K,V} = TupleDict{K,V}(first.(ps), last.(ps))
Base.keys(d::TupleDict) = d.ks
Base.values(d::TupleDict) = d.vs
function Base.get(d::TupleDict{K,V}, key::K, default) where {K,V}
for i in 1:length(d.ks)
candidate = @inbounds d.ks[i]
isequal(candidate, key) && return @inbounds d.vs[i]::V
end
return default
end
Base.iterate(d::TupleDict, i=1) =
i ≤ length(d.ks) ? (d.ks[i] => d.vs[i], i + 1) : nothing
At first I was quite happy with it, but now I am running into a problem with nested completion in the REPL not working:
struct Foo
x::TupleDict{Symbol,Union{Foo,Nothing}}
end
Foo(xs::Vararg{Pair}) = Foo(TupleDict{Symbol,Union{Nothing,Foo}}(xs...))
content(f::Foo) = getfield(f, :x)
Base.propertynames(f::Foo) = f |> content |> keys
Base.getproperty(f::Foo, s::Symbol) = content(f)[s]
f = Foo(:abc => nothing, :def => Foo(:xyz => nothing))
If I type f.a<TAB> it completes, but for f.def.x<TAB> it does not.
In contrast, if I would use OrderedCollections: OrderedDict for the same Foo example, it completion works also in the nested case.
Why does inference fail for my simple TupleDict?
Any kind of criticism beyond this question is also greatly appreciated!