I need to define two mutually circular types. I have read this issue, which suggests using a forward declaration. That works. However, I also need to contain the types in Dicts, which must be initialised.
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.
# 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.
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 :
function B()
self = new()
self.adict = Dict{String, A}()
self
end
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.