I am writing my first module and have several data structures that will be all linked to each other, sort of like blog posts and comments. I have a file for each data structure that will house methods relevant to each. The following code doesn’t work as the compiler doesn’t know what a Comment data type is when it parses the Post struct.
File Blog.jl
module Blog
include("post.jl")
include("comment.jl")
end
File post.jl
struct Post
comments::Vector{Comment}
end
File comment.jl
struct Comment
post::Post
end
Since the include command is a simple copy paster, adding include statements in every file doesn’t work either, as it creates an infinite loop.
It seems to me that the problem is the definition of the types.
There is no place to stop when interpreting the types: it is recursive all the way down to the turtles.
So what is the most effective way of implementing this design pattern in Julia? I’ve played around a bit and here is what I found:
Undef: Post not defined
struct Comment
post::Post
end
struct Post
comments::Vector{Comment}
end
but if you use generics, then it works
struct Post{C <: Vector}
comments::C
end
struct Comment
post::Post
end
I’ve even thought of a completely different design pattern like this:
struct Post
author_id::Int
text::String
end
struct Comment
user_id::Int
text::String
end
struct PostComments
post::Post
comments::Vector{Comment}
end
Perhaps this is the preferred way to implement this? But it would be so inefficient without any way of being able to query the parent post like so my_comment.post.
abstract type AbstractComment end
abstract type AbstractPost end
struct Comment{P <: AbstractPost} <: AbstractComment
post::P
end
struct Post{C <: AbstractComment} <: AbstractPost
comments::Vector{C}
end
Thanks. Can you remove the use of abstract comment and use the actual Comment type since it gets defined first? Compiler only needed one of them in my test.
And tangential question - where do I instantiate the empty Comment[] array? Pass it to the default constructor? I wasn’t able to do something Iike C[] in an inner constructor.
julia> abstract type AbstractComment end
julia> abstract type AbstractPost end
julia> struct Comment{P <: AbstractPost} <: AbstractComment
post::P
end
julia> struct Post{C <: AbstractComment} <: AbstractPost
comments::Vector{C}
Post(comments::Vector{C} = Comment[]) where C <: AbstractComment = new{C}(comments)
end
julia> Post()
Post{Comment}(Comment[])
julia> Post(AbstractComment[])
Post{AbstractComment}(AbstractComment[])
Yes, but now we’re not following the design pattern.
abstract type AbstractPost end
struct Comment{P <: AbstractPost}
post::P
end
struct Post<: AbstractPost
comments::Vector{Comment}
end
Post() = Post(Comment[])