# I want to replicate with Named Tuples what I do with Dictionaries but I can't

**URL:** <https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522>\
**Category:** General Usage\
**Tags:** dictionary, namedtuple\
**Created:** [October 27, 2021, 11:07pm UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522 "2021-10-27T23:07:51Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Soldalma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soldalma/32/29388_2.png) [@Soldalma](https://discourse.julialang.org/u/Soldalma)\
**Post date:** [October 27, 2021, 11:07pm UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/1 "2021-10-27T23:07:51Z")

</div>

I wrote some code that fills an array of dictionaries step by step.  
I did not use Int64 for the values because in “real life” I do not know the types of the values in advance.

```julia
my_dicts = [Dict{String,Any}() for _ in 1:3]

for i in 1:length(my_dicts)
    my_dicts[i] = Dict("A"=> i, "B" => i + 1)
    println(my_dicts[i])
end

```

The code above works fine.

I wanted to do something similar with named tuples. So I tried this:

```julia
my_tups = [NamedTuple{(:A, :B), Tuple{Int64, Int64}}() for _ in 1:3]

for i in 1:length(my_tups)
    my_tups[i] = (A = i, B = i + 1)
    println(my_tups[i])
end

```

This did not work even though I specified the type of the second element of each pair. I got the following message in the REPL:

```julia
julia> my_tups = [NamedTuple{(:A, :B), Tuple{Int64, Int64}}() for _ in 1:3]
ERROR: MethodError: no method matching NamedTuple{(:A, :B), Tuple{Int64, Int64}}()

```

Any hints on how to prepare an array to receive the named tuples generated in the for loop?

Thanks.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 28, 2021, 12:59am UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/2 "2021-10-28T00:59:00Z")

</div>

Try

```julia
Vector{NamedTuple{(:A, :B), Tuple{Int64, Int64}}}(undef, 3)

```

Your version tries to create instances of the named tuples without any data, which does not appear to be supported.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 28, 2021, 1:07am UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/3 "2021-10-28T01:07:46Z")

</div>

> [@baggepinnen](#):
>
> `Vector{NamedTuple{(:A, :B), Tuple{Int64, Int64}}}(undef, 3)`

Easier syntax: `Vector{@NamedTuple{A::Int,B::Int}}(undef, 3)`

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 28, 2021, 1:42am UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/4 "2021-10-28T01:42:58Z")

</div>

Dictionaries are mutable (alterable) by nature and by design.

```julia
mydict = Dict{String,Int}()
isempty(mydict) === true
mydict["A"] = 1
isempty(mydict) === false
length(mydict) === 1
mydict["B"] = 2
length(mydict) === 2
mydict["B"] === 2
mydict["B"] = 22
length(mydict) === 2
mydict["B"] === 22

```

NamedTuples are static (immutable, fixed) by nature and by design. NamedTuples really are Tuples with Names. The Names are given to each of the Tuple’s places, in the sequence that the Tuple’s values appear.

You can create an empty NamedTuple, however once created it cannot be modified (you cannot add a new field). If you know the field names that your NamedTuples will use, then you can establish that pattern of field names as a “prototype” of a NamedTuple [here, prototype is a suggestive term that really refers to an incompletely specified Type of a NamedTuple].

```julia
fieldnames = (:A, :B, :C) # they must be `Symbols`
proto_nt = NamedTuple{fieldnames}

# get the field's values until you have all of them
first_fieldvalues = [1, 2, 3]; # a Vector of values
# or, if you have all the field's values at once
second_fieldvalues = (11, 22, 33); # a value Tuple

my_first_nt = proto_nt(first_fieldvalues)
my_second_nt = proto_nt(second_fieldvalues)

```

```julia
julia> my_first_nt = proto_nt(first_fieldvalues)
(A = 1, B = 2, C = 3)

julia> my_second_nt = proto_nt(second_fieldvalues)
(A = 11, B = 22, C = 33)

```

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 28, 2021, 7:02am UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/5 "2021-10-28T07:02:32Z")

</div>

`I can get you close to what you intended.  
We use the fact that ordinary Vectors  
are mutable, one may overwrite the value  
currently held any of the vector’s indices.

So, the first insight is to use a Vector  
to carry the (initially) empty NamedTuples.  
Let’s try.  
[`(;)` is how to write an empty NamedTuple]

{copy and paste the examples into the REPL}

```julia
n_empty_namedtuples(n) = [(;) for i in 1:n]

two_empty_namedtuples = n_empty_namedtuples(2)

```

the second line gives the result

```julia
2-element Vector{NamedTuple{(), Tuple{}}}:
 NamedTuple()
 NamedTuple()

```

That means `two_empty_namedtuples` is a  
vector of 2 elements, and these elements  
are each typed `NamedTuple{(), Tuple{}}`.

… aside, a look at how the type is given

[while that type looks unusual, it is  
just a parameterized type with two  
parameters: the first parameter is  
a Tuple (here, it is empty) and the  
second parameter is a Tuple Type,  
(here it is a Tuple Type with no elements).  
see the docs about Parametric types.

Let’s look at a NamedTuple that has content:

```julia
  nt = (A = 1, B = 2)
  typeof_nt = typeof(nt);

  fieldnames(typeof_nt) == (:A, :B)
  fieldtypes(typeof_nt) == (Int64, Int64)
  
   # the typeof() a NamedTuple is like this
   #
   # NamedTuple{ (fieldnames as symbols), 
   # Tuple{ fieldtypes } }
   #
   typeof_nt == 
     NamedTuple{ (:A, :B), 
                  Tuple{Int64, Int64} }

```

We created `two_empty_namedtuples`.

Next, you want to replace the empty  
NamedTuples with new NamedTuples.  
[all sharing the same fieldnames and  
fieldtypes … differing in their values

- all are of the same length,
- all have the same keys in the same order,
- each may assign its own values to the keys]

We can try, but this

```julia
new_namedtuple = (A = 1, B = 2)
two_empty_namedtuples[1] = new_namedtuple

```

generates a MethodError

```julia
 (1) "Cannot `convert` an object of type
 (2) NamedTuple{(:A, :B),Tuple{Int64,Int64}}
 (3) to an object of type
 (4) NamedTuple{(),Tuple{}}"

```

The `typeof(new_namedtuple)` is  
`NamedTuple{(:A, :B),Tuple{Int64,Int64}}`  
and this is written on line (2).  
The `typeof( (;) )` is  
`NamedTuple{(), Tuple{}}`  
and this is written on line (4)

The MethodError says when we tried to  
overwrite the empty NamedTuple with  
the new\_namedtuple, Julia looked at  
each value’s type and found they were  
incompatable. To use a new NamedTuple  
to overwrite one already present within  
a Vector, the two NamedTuples must be  
of matching type.

For two NamedTuple types to match, both must  
have the same length, the same fieldnames,  
the same ordering of the fieldnames, and  
the same fieldtypes with the same ordering.  
Their values may differ, as long as the  
value’s types are the same.

Well, the empty NamedTuples certainly  
do not have the same lenghts as the  
new NamedTuples that are to replace them.

Fortunately, NamedTuple types without  
any fieldnames or fieldtypes specified  
is a special flavor in the land of types:

This is different from empty NamedTuple  
types, we have not constrained the  
number of fields that there may be,  
only insisted that information is not  
present when given the “bare” type `NamedTuple` (the type absent parameters,  
the name for this kind of type is UnionAll  
because it represents the union of all  
possible legal parameterizations).

That allows us to do this

```julia
n_empty_namedtuples(n) =
  NamedTuple[(;) for i in 1:n]

two_namedtuples = n_empty_namedtuples(2)

new_namedtuple = (A = 1, B = 2)
two_namedtuples[1] = new_namedtuple

two_namedtuples[1] == new_namedtuple
two_namedtuples[2] == (;)

```

How is the MethodError avoided?  
Look at what we did:

```julia
errorful = [(;), (;)];
successful = NamedTuple[(;), (;)];

eltype(errorful) == NamedTuple{(), Tuple{}
eltype(successful) == NamedTuple

```

The errorful version has an eltype that  
is a NamedTuple type with parameters given  
[the parameters are () and Tuple{}].

The successful version has an eltype that  
is a UnionAll NamedTuple type (no parameters).

As a UnionAll type is implicitly gathering  
all possible legitimate parameterizations  
(the way each parameter is given, is set),  
the specific set of parameter values that  
happens to belong to `typeof(new_namedtuple)`  
is among the “all possible”, so assignment  
(overwriting) works.

```julia
n_empty_namedtuples(n) =
  NamedTuple[(;) for i in 1:n]

my_tups = n_empty_namedtuples(3)

ok = all( isempty.(my_tups) ) &&
     length(my_tups) == howmany

for i in 1:length(my_tups)
    my_tups[i] = (A = i, B = i+1)
    println(my_tups[i])
end
# (A = 1, B = 2)
# (A = 2, B = 3)
# (A = 3, B = 4)

```

As it stands, each element of the vector my\_tups remains open  
to being overwritten by any other NamedTuple, compatible or not:

```julia
copyof_my_tups = deepcopy(my_tups)

incompat1 = (X = 3, Y = 2, Z = 1)
incompat2= (B = 'b', A = 'a')

copyof_my_tups[1] = incompat1
copyof_my_tups[2] = incompat2
copyof_my_tups
# 3-element Vector{NamedTuple}:
# (X = 3, Y = 2, Z = 1)
# (B = 'b', A = 'a')
# (A = 3, B = 4)

```

Here is a way to obtain a new vector not allowing incompatible overwrites,

```julia
typeconstraint = typeof(my_tups[1])
# NamedTuple{(:A, :B), Tuple{Int64, Int64}}

welldressed = typeconstraint[my_tups...]
# 3-element Vector...
# (A = 1, B = 2)
# (A = 2, B = 3)
# (A = 3, B = 4)

welldressed[1] = incompat1
# MethodError: Cannot `convert` an object of type ...

```

---

<div class="post-metadata">

**Author:** ![Soldalma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soldalma/32/29388_2.png) [@Soldalma](https://discourse.julialang.org/u/Soldalma)\
**Post date:** [October 28, 2021, 9:57pm UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/7 "2021-10-28T21:57:07Z")

</div>

> [@baggepinnen](#):
>
> `Vector{NamedTuple{(:A, :B), Tuple{Int64, Int64}}}(undef, 3)`

That was exactly what I needed. Thanks. Following your suggestion I was able to replace a dictionary with a named tuple, hoping my program was going to run faster because dictionaries are mutable and named tuples are immutable. But I did not notice a difference in speed. The dictionary was the return value of a function that is called many times.

---

<div class="post-metadata">

**Author:** ![Soldalma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soldalma/32/29388_2.png) [@Soldalma](https://discourse.julialang.org/u/Soldalma)\
**Post date:** [October 28, 2021, 10:03pm UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/8 "2021-10-28T22:03:19Z")

</div>

Thanks for the extensive lesson. I read the Types section of the documentation and did not “get” all of it. Reading it again is a priority. After doing it I will come back to read again your post.

In practice my Julia project is moving ahead fine, so not understanding all the complexities of types has not been a big obstacle, thanks to the help I keep getting here in Discourse.

---

<div class="post-metadata">

**Author:** ![Soldalma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/soldalma/32/29388_2.png) [@Soldalma](https://discourse.julialang.org/u/Soldalma)\
**Post date:** [November 2, 2021, 1:02am UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/9 "2021-11-02T01:02:46Z")

</div>

Thanks. I learned quite a lot.

It is still not completely clear to me why writing NamedTuple before the square brackets solves the problem. Is this just an arbitrary convention for this particular case or is it an application of a general rule?

On a side note, I also did not understand this: `all( isempty(my_tups) )`. I believe the return value of `isempty(my_tups)` will have length 1, so the `all` is not needed. The `ok` variable turns out to be false. Doing it this way `all(map(isempty, my_tups))` I got it to be true.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [November 9, 2021, 7:48am UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/11 "2021-11-09T07:48:30Z")

</div>

> [@Soldalma](#):
>
> I also did not understand this: `all( isempty(my_tups) )` . I believe the return value of `isempty(my_tups)` will have length 1, so the `all` is not needed. The `ok` variable turns out to be false. Doing it this way `all(map(isempty, my_tups))` I got it to be true.

I had omitted the broadcasting ‘all( isempty.(my\_tups))’, that is corrected. Your approach works well, too. I use both, depending on the emphasis.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [November 9, 2021, 7:51am UTC](https://discourse.julialang.org/t/i-want-to-replicate-with-named-tuples-what-i-do-with-dictionaries-but-i-cant/70522/12 "2021-11-09T07:51:48Z")

</div>

> It is still not completely clear to me why writing NamedTuple before the square brackets solves the problem. Is this just an arbitrary convention for this particular case or is it an application of a general rule?

It is a more advanced use of the Julia type system. As you may recall,  
the generalized type called `NamedTuple` (without any parameters) is itself a `UnionAll` type:

```julia
julia> nt = (A = 1, B = 2)
(A = 1, B = 2)

julia> typeof(nt)
NamedTuple{(:A, :B), Tuple{Int64, Int64}}

julia> nameof(typeof(nt))
:NamedTuple

julia> typeof(NamedTuple) # or typeof(eval(ans))
UnionAll

```

UnionAll types are types that implicitly range over _all_ possible specific values of their implicit parameters. So using `NamedTuple[..]` creates an array of `NamedTuples{(<names>), Tuple{<types>}}` that conform to the contents of the elements of the vector. For your purposes they should all be the same `eltype(vector)` .

Think of it as inquiring what kind of NamedTuple the elements’ are, and then placing the (consistently used) names into the first parameter and the (consistently used) types into the second parameter. Since our vector is initialized as a vector of `NamedTuple[..]` , without any parameters, it will accept all possible NamedTuples – not just all of one given sort (but, really, this is for information only – to use what follows is bad practice in most cases).

```julia
julia> two_namedtuples = n_empty_namedtuples(2)
# Vector{NamedTuple}: NamedTuple(), NamedTuple()

julia> two_namedtuples[1] = (A = 1, B = 2);
(A = 1, B = 2)

julia> typeof(anstwo_namedtuples[1])
NamedTuple{(:A, :B), Tuple{Int64, Int64}}

julia> two_namedtuples[2] = 
       (NotA = 'b', NotB = "notb", C = 3);
(NotA = 'b', NotB = "notb", C = 3)

julia> typeof(anstwo_namedtuples[2])
NamedTuple{(:NotA, :NotB, :C), 
           Tuple{Char, String, Int64}}

julia> two_namedtuples
2-element Vector{NamedTuple}:
 (A = 1, B = 2)
 (NotA = 'b', NotB = "notb", C = 3)

julia> typeof(ans)
Vector{NamedTuple} (alias for Array{NamedTuple, 1})

```
