# Initialise a dict in a mutually circular type

**URL:** https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476
**Category:** New to Julia
**Created:** [June 15, 2020, 10:32pm UTC](https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476 "2020-06-15T22:32:03Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![nacnudus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nacnudus/32/15762_2.png) [@nacnudus](https://discourse.julialang.org/u/nacnudus)
#### Post date: [June 15, 2020, 10:32pm UTC](https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476/1 "2020-06-15T22:32:03Z")

</div>

I need to define two mutually circular types. I have read this [issue](https://github.com/JuliaLang/julia/issues/269), which suggests using a forward declaration. That works. However, I also need to contain the types in `Dict`s, which must be initialised.

```nohighlight
abstract type AbstractB end

mutable struct A
  b::AbstractB
  A() = new()
end

mutable struct B <: AbstractB
  a::A
  adict::Dict{String, A}
  B() = new()
end

a = A()
b = B()

# This works
a.b = b
b.a = a

# But this gives an error, because the dictionary wasn't initialised.
b.adict["1"] = a
# ERROR: UndefRefError: access to undefined reference

```

This time, I use an inner constructor to initialise the `Dict` to an empty dictionary. It seems to recursively call the circular types, even though the dictionary is empty.

```nohighlight
# NEW SESSION =========================

# This time, initialize the dictionary with an empty dictionary.

abstract type AbstractB end

mutable struct A
  b::AbstractB
  stringdict::Dict{String, AbstractB}
  A() = new(B(), Dict{String, B}())
end

mutable struct B <: AbstractB
  a::A
  adict::Dict{String, A}
  B() = new(A(), Dict{String, A}())
end

a = A() # StackOverflowError. Why, given that the dict has zero entries?

```

Is there a way around this? I’d really like to use the types, because these structures will be used a lot.

---

<div class="post-metadata">

### Author: ![anon94023334](https://avatars.discourse-cdn.com/v4/letter/a/e274bd/32.png) [@anon94023334](https://discourse.julialang.org/u/anon94023334)
#### Post date: [June 15, 2020, 10:36pm UTC](https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476/2 "2020-06-15T22:36:58Z")

</div>

> [@nacnudus](#):
>
> `Why, given that the dict has zero entries?`

Because your constructor for `A()` calls `B()`, which is the inner constructor for `B`, which calls `A()`, the inner constructor for which calls `B()`,…

---

<div class="post-metadata">

### Author: ![nacnudus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nacnudus/32/15762_2.png) [@nacnudus](https://discourse.julialang.org/u/nacnudus)
#### Post date: [June 15, 2020, 10:40pm UTC](https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476/3 "2020-06-15T22:40:46Z")

</div>

Thanks. I’d like to not initialise `a` or `b`, but that doesn’t seem to be possible. I tried an inner constructor, but it had the original `UndefRefError` problem :

```nohighlight
function B()
  self = new()
  self.adict = Dict{String, A}()
  self
end

```

---

<div class="post-metadata">

### Author: ![anon94023334](https://avatars.discourse-cdn.com/v4/letter/a/e274bd/32.png) [@anon94023334](https://discourse.julialang.org/u/anon94023334)
#### Post date: [June 15, 2020, 10:42pm UTC](https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476/4 "2020-06-15T22:42:13Z")

</div>

One possible workaround is to make `B.a` a union of `A, Nothing` and have the default constructor set `a` to `nothing`.

Also, [this might help](https://docs.julialang.org/en/v1/manual/constructors/#Incomplete-Initialization-1).

---

<div class="post-metadata">

### Author: ![nacnudus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nacnudus/32/15762_2.png) [@nacnudus](https://discourse.julialang.org/u/nacnudus)
#### Post date: [June 15, 2020, 10:54pm UTC](https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476/5 "2020-06-15T22:54:30Z")

</div>

That works. Also I just realised you’re the author of LightGraphs, which inspired me to try Julia. Thank you on both counts!

I had read that link before, and it lost me at “As with incomplete objects returned from constructors, if `complete_me` or any of its callees try to access the `data` field of the `Lazy` object before it has been initialized, an error will be thrown immediately.” It seems to recommend delegating completion to a function that isn’t allowed to access the incomplete data field.

---

<div class="post-metadata">

### Author: ![anon94023334](https://avatars.discourse-cdn.com/v4/letter/a/e274bd/32.png) [@anon94023334](https://discourse.julialang.org/u/anon94023334)
#### Post date: [June 16, 2020, 5:40am UTC](https://discourse.julialang.org/t/initialise-a-dict-in-a-mutually-circular-type/41476/6 "2020-06-16T05:40:52Z")

</div>

> [@nacnudus](#):
>
> Also I just realised you’re the author of LightGraphs, which inspired me to try Julia.

Thanks very much for this. I hope it’s working for you.

> [@nacnudus](#):
>
> I had read that link before, and it lost me at “As with incomplete objects returned from constructors, if `complete_me` or any of its callees try to access the `data` field of the `Lazy` object before it has been initialized, an error will be thrown immediately.”

I wouldn’t worry too much about that part. Basically, it just means this:

```julia
julia> mutable struct A
       x::String
       A() = new()
       end

julia> z = A()
A(#undef)

julia> z.x
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty(::A, ::Symbol) at ./Base.jl:33

julia> z.x = "hello, world!"
"hello, world!"

julia> z
A("hello, world!")

```

(Note that if `x` is an `Integer` or some other primitive (?) type, it will receive an invalid, as opposed to undefined, value:

```julia
julia> mutable struct A                                                                                                                               
       x::Int                                                                                                                                         
       A() = new()
       end

julia> z = A()
A(140069649368400)

```

)
