Make tab-explorable structure from nested Dict

For nothing but the sake of my own and potential users convenience when REPL:ing around, I’d like to turn a nested Dict with symbol keys into something which can be tab-completed all the way down to the leaves.

I have made some experiments with wrapping the Dict in a struct and implementing getproperty and propertynames according to the documentation but I can’t get it to propagate to the nested Dicts/structs. I’m guessing it is because I could not make the return type of getproperty inferable.

Translating the nested Dict to a nested NamedTuple makes the result tabbable in the desired way with the one remaining issue that I’d like to be able to override some base methods, in particular show, and trying to wrap the NamedTuple in a struct puts me back at sqaure one unless I accept an unatural extra hop (i.e `data.wrappednamedtuple.a.wrappednamedtuple.b…).

As a hacky workaround, a marker type and a type alias seems to get me what I want, with the perhaps overcomeable cost that one needs to remember to ignore the first element:

struct Marker end
MyTabbableStruct{T} = NamedTuple{T, <:Tuple{Marker, Vararg}}

Base.propertynames(t::MyTabbableStruct{T}, private=false) where T = private ? T : T[2:end] 

astabbable(d::Dict) = (;:first=>Marker(), (k => astabbable(v) for (k,v) in d)...)
astabbable(x) = x

julia> tabbable = astabbable(Dict(:a=>1, :b=>2,:c=>Dict(:d=>3, :e=>Dict(:f=>4))));

julia> tabbable.c. [press tab]
d e

This seems unecessarily convoluted though. Are there other ways to achieve the same thing?

1 Like

There is the package PropDicts.jl that may be helpful.

3 Likes

Unfortunately it has the same problem as my first alternative. It does not seem to be anything more than a Dict in a struct and I think julia can’t infer the type of getproperty.

Is there something one can do to get the same behaviour as NamedTuple given a Dict? In case it matters, the number of types the values can have is bounded but not union-splitting small. Its basically most Number types, Dicts and vectors of those.

Did you ever find a better solution to this?
I also wanted to achieve something similar with custom struct containing named tuples but found this issue of “tabbability” after the first layer.
I also tried your working example and verified that it works but I can’t seem to understand how adding this Marker would make it so.
If not too much of a hassle, could you please share some info/insights on why this woud allow the tabbability?

Hi,

I have put this issue aside for now as I was not in need of a real solution.

Adding Marker is not what makes it tabbable, its just and ad-hoc (ad-hack?) way of making the result of astabbable a type owned by me (i.e MyTabbableStruct) so I can define e.g. Base methods for it without it being type piracy. This comes at the cost of having to keep pretending it is not there and I’m sure it is against a couple of other conventions as well so it is not really something I would recommend.

If you don’t need this, just use a normal named tuple all the way.

The code that makes completions work is here.
You might be able to find a way to convince it to do what you want.
Or monkey-patch it to do what you want.

2 Likes