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!