I’m trying to build two tree node types that keep track of a set of instances of each other.
FooNode{T, C <: Set}
childs::C
foo::T
end
BarNode{G, D <: Set}
childs::D
bar::G
end
T and G are other parametric types that we know at construct time. The constructor methods would thus be Foo(foo::T) and Bar(bar::G). After construction, the type of Foo should look like Foo{T, Set{Bar{G, Set{Foo{T, ...}}}}}.
I don’t understand how to make the inner constructors for these two functions. Specifically, I don’t understand how to make the new{...} call with the correct parameters because of the recursion.
julia> struct FooNode{T, C <: Set}
childs::C
foo::T
end
julia> struct BarNode{G, D <: Set}
childs::D
bar::G
end
julia> b1 = BarNode(Set(), 4)
BarNode{Int64, Set{Any}}(Set{Any}(), 4)
julia> FooNode(Set(b1=>4.0), 6)
FooNode{Int64, Set{Union{Float64, BarNode{Int64, Set{Any}}}}}(Set(Union{Float64, BarNode{Int64, Set{Any}}}[BarNode{Int64, Set{Any}}(Set{Any}(), 4), 4.0]), 6)
Just note that it likely is not a good idea to use such a complicated, nested type architecture since it might cause huge compile times. You should treat “putting information into the type domain” as a potential optimization that comes with drawbacks and needs to evaluated in a case-by-case basis. If you have already working code that you deem too slow and this is an attempt at optimization, then I’d recommend asking for help with your working code directly. If you develop something from scratch then I’d recommend taking a simpler approach since it is unclear whether the complex type shenanigans will pay off.
Sorry I was in a hurry when I wrote the OP. I’d like to write the constructor in a way that avoids the Any types. You can do self-referencial types if they are non-parametric (Constructors · The Julia Language) but I can’t figure it out for parametric types.
But if it’s impossible then I’ll find another way.
There are workarounds (e.g. abstract types and mutable structs) which you probably won’t like even though they are likely cheap from a runtime perspective.
Beware of trying to use parametric types like this for a tree, because then you are encoding the tree structure into the type — every distinct tree structure will have a distinct type, forcing the compiler to recompile/specialize code for every tree.
I would suggest backing up a bit and describing what kind of data structure you would like to end up with: ie the typical operations and access patterns, and relevant type parameters for the data.
Generally you can avoid deeply nested recursive types by parametrizing the field indirectly. See eg DataStructures.LinkedList. But it is not necessarily the ideal solution in Julia for most problems, compared to eg Common Lisp.