# Tuple-based (immutable, ordered) Dictionary and nested REPLCompletion

**URL:** <https://discourse.julialang.org/t/tuple-based-immutable-ordered-dictionary-and-nested-replcompletion/121004>\
**Category:** General Usage\
**Tags:** question, repl, compiler\
**Created:** [October 7, 2024, 12:23pm UTC](https://discourse.julialang.org/t/tuple-based-immutable-ordered-dictionary-and-nested-replcompletion/121004 "2024-10-07T12:23:16Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![marquito](https://avatars.discourse-cdn.com/v4/letter/m/ee7513/32.png) [@marquito](https://discourse.julialang.org/u/marquito)\
**Post date:** [October 7, 2024, 12:23pm UTC](https://discourse.julialang.org/t/tuple-based-immutable-ordered-dictionary-and-nested-replcompletion/121004/1 "2024-10-07T12:23:16Z")

</div>

Hi!  
Since I couldn’t find a tuple-based (immutable and ordered) dictionary I came up with the following:

```julia
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:

```julia
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!

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [October 7, 2024, 12:51pm UTC](https://discourse.julialang.org/t/tuple-based-immutable-ordered-dictionary-and-nested-replcompletion/121004/2 "2024-10-07T12:51:02Z")

</div>

> [@marquito](#):
>
> tuple-based dictionary

See LittleDict in OrderedCollections.jl or [Dictionaries.jl/contrib/TupleDictionaries.jl at master · andyferris/Dictionaries.jl · GitHub](https://github.com/andyferris/Dictionaries.jl/blob/master/contrib/TupleDictionaries.jl).

---

<div class="post-metadata">

**Author:** ![marquito](https://avatars.discourse-cdn.com/v4/letter/m/ee7513/32.png) [@marquito](https://discourse.julialang.org/u/marquito)\
**Post date:** [October 7, 2024, 3:48pm UTC](https://discourse.julialang.org/t/tuple-based-immutable-ordered-dictionary-and-nested-replcompletion/121004/3 "2024-10-07T15:48:51Z")

</div>

Thanks @aplavin! I just tried the `Foo` example for nested completion with `OrderedCollections: LittleDict` and it turns out that completion also doesn’t work. This suggests that the problem might be more fundamental.
