Absence of method to convert NamedTuple -> Dictionary?

Is there a reason why we don’t and/or can’t have a method that converts a named tuple into a Dictionary? Currently passing a named tuple to a Dictionary constructor simply errors as there is no defined method. The solution is to use pairs to iterate over the named tuple and pass that iterator into the constructor. It seems difficult to imagine what other behavior a user could want from passing a named tuple to a Dictionary though. Maybe there are edge cases that wouldn’t behave nicely?

julia> nt = (; a=1, b=2)
(a = 1, b = 2)

julia> Dict(nt)
ERROR: ArgumentError: AbstractDict(kv): kv needs to be an iterator of 2-tuples or pairs
Stacktrace:
[1] _throw_dict_kv_error()
   @ Base ./abstractdict.jl:583
[2] grow_to!(dest::Dict{Any, Any}, itr::@NamedTuple{a::Int64, b::Int64})
   @ Base ./abstractdict.jl:595
[3] dict_with_eltype(DT_apply::Base.var"#421#422", kv::@NamedTuple{a::Int64, b::Int64}, t::Type)
   @ Base ./abstractdict.jl:635
[4] Dict(kv::@NamedTuple{a::Int64, b::Int64})
   @ Base ./dict.jl:117
[5] top-level scope
   @ REPL[2]:1

julia> Dict(pairs(nt))
Dict{Symbol, Int64} with 2 entries:
  :a => 1
  :b => 2

julia> pairs(nt)
pairs(::NamedTuple) with 2 entries:
  :a => 1
  :b => 2

julia> Dict(nt::NamedTuple) = Dict(pairs(nt))
Dict

julia> Dict(nt)
Dict{Symbol, Int64} with 2 entries:
  :a => 1
  :b => 2

Dictionaries support NamedTuples directly, it’s Dicts that don’t :slight_smile:

julia> using Dictionaries

julia> nt = (; a=1, b=2)
(a = 1, b = 2)

julia> Dictionary(nt)
2-element Dictionary{Symbol, Int64}:
 :a │ 1
 :b │ 2
1 Like

I had wondered if Dictionaries.jl would handle this. I briefly skimmed the About section on Github and didn’t see it in the examples but didn’t bother to install the package to test it myself. Nice to know that it does!

Regardless, this doesn’t answer the question of whether Base.Dict could have this method as well. (And I’d prefer to keep this thread from turning into a discussion on the relative merits of Base.Dict vs Dictionaries.jl)

1 Like

Unfortunately, adding Dict(::NamedTuple) that works like you suggest would be breaking. It already has a behavior, same as for other iterables:

julia> nt = (; a=:x => 1, b=:y => 2)

julia> Dict(nt)
Dict{Symbol, Int64} with 2 entries:
  :y => 2
  :x => 1
3 Likes

Ah I see. Somewhere in the machinery of Base.Dict it is trying to iterate the NamedTuple but NamedTuples when iterated, produce their values not their key/value pairs and so it doesn’t play nice with what Base.Dict requires. And changing that would technically be breaking because someone could hypothetically be relying on the behavior (of having a named tuple of pairs) that you demonstrated.

So yeah, just one of those unfortunate side effects of various parts interacting.

4 Likes