`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}

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

the second line gives the result

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

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

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

generates a MethodError

```
(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

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

```
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.

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

```
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,

```
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 ...
```