Get keypath on a dict

Is there a reason why put supports keypaths and get doesn’t?

I think the code is actually there, from the first look all is needed is some additional plumbing in eval_dict_function in boot/dicts.pl.

Because you can write Dict.x.y.z as well as Dict.get(x).get(y). For put this doesn’t work as we need to update all dicts along the path.

But yes, we could also add Dict.get(x/y) for symmetry. I’m not against that, although it looks a bit odd. Did other people miss this?

Considering defaults, yip. A Dict.get(X, Default) makes sense, although I’m inclined to use a different name, e.g. Dict.get_else(X, Default). I’m not really happy with get_else either. Better suggestions?

I think key paths are much more reusable in general than chaining gets.

One example where I relied on this is a small csv writer library that works so that you pass it a list of keypaths and a continuation. It then uses delimited continuations to “receive” dictionaries, extracts the list of keypaths from them and writes lines to csv file. When there are no more shifts csv file is closed and writing is done, but also you can flush data manually. This way you don’t have to have a complete list of data before you can write, and can write lines as data arrives/is being processed, potentially in a neverending loop.

Another more frequent use case, is the update of fields in the dictionary. It’s usually a get, then some modification followed by a put of the value into dictionary for the same key. In case of nested keys (keypaths), you have to define it twice then, once in the .get(foo).get(bar) syntax and then as foo/bar for the put, or use two puts which is peak cumbersome :slight_smile:

I think keypaths for get would be very useful addition that is not introducing any new syntax or predicates. If we implement this correctly, I think the keypaths would then just work in get_dict/5 too.

Defaults would also be nice to have, get(Key, Default) syntax would be somewhat consistent with option/3 which is also not called option_else :slight_smile:

Being able to reuse of key-path for get and put is convincing. Added. None of the non-function dict predicates support key paths. I’m not sure I want them there either.

I did add get(Key, Default). If Key is unbound or is a path holding unbound components this still generates all solutions on backtracking and only uses Default if there are no solutions. Not entirely clear whether this is the best choice or not. In practice it probably doesn’t matter much.

Don’t consider this set in stone yet. If someone comes with a good argument to do things a bit differently, that may happen.

3 Likes