That seems likely to work, though obviously some operations will not be
inferrable. You might be just as happy with
type PhylogenyNode
kind::Symbol # :clade, etc.
from::PhyologenyEdge
to::Vector{PhylogenyEdge}
confidence::Float64
end
type PhylogenyEdge
kind::Symbol # :branch, etc.
from::PhylogenyNode
to::PhylogenyNode
end
and then manually dispatching on "kind". Here, everything is inferrable.
A favorite trick (not my invention, of course) is to have root nodes point to
themselves, so that you don't have to define a separate type for empty.
Something to consider seriously is using an established package like
LightGraphs and storing any metadata separately. If you really want/need
separate types for the different nodes, one advantage of this strategy is that
at least graph traversal will be fast (inferrable)---it's only the metadata
lookup that will be type-unstable.
--Tim
On Thursday, August 25, 2016 3:26:39 AM CDT Ben Ward wrote:
> Hi Tim,
>
> That's a shame, I was hoping that doing the above would let me create
> several different concrete PhylogenyNode and PhylogenyEdge types, that can
> be used together. I guess since this is an abuse I have to pair one
> concrete PhylogenyEdge type with one concrete PhylogenyNode type? I
> wondered is a valid alternative to do something like this:
>
> abstract AbstractNode
> abstract PhylogenyNode <: AbstractNode
> abstract NetworkNode <: AbstractNode
> abstract AbstractEdge
> abstract PhylogenyEdge <: AbstractEdge
> abstract NetworkEdge <: AbstractEdge
>
> type Branch <: PhylogenyEdge
> from::PhylogenyNode
> to::PhylogenyNode
> length::Float64
>
> function Branch()
> x = new()
> length!(x, -1.0)
> return x
> end
> end
>
> type Clade <: PhylogenyNode
> from::PhylogenyEdge
> to::Vector{PhylogenyEdge}
> confidence::Float64
>
> function Clade()
> x = new()
> x.to = Vector{PhylogenyEdge}()
> confidence!(x, -1.0)
> return x
> end
> end
>
> And define getters and setters in such a way that type assertions make
> things certain for the compiler?
> I saw that Jeff proposed a similar solution in julia issue #269 to handle
> circular type declarations.
>
> On Wednesday, August 24, 2016 at 4:11:06 PM UTC+1, Tim Holy wrote:
> > I don't think that's type-stable. Since each node of each tree will also
> > be a
> > different type, I also think you'll end up hating life due to compile
> > times.
> > There's some (peripherally) relevant discussion at
> > http://docs.julialang.org/
> >
> > en/latest/manual/performance-tips/#the-dangers-of-abusing-multiple-dispatc
> > h-
> >
> > aka-more-on-types-with-values-as-parameters
> > <http://docs.julialang.org/en/latest/manual/performance-tips/#the-dangers->
> > > of-abusing-multiple-dispatch-aka-more-on-types-with-values-as-parameters>
> >
> > Best,
> > --Tim
> >
> > On Tuesday, August 23, 2016 3:28:17 PM CDT Ben Ward wrote:
> > > I'm doing some development and wondered if this kind of pattern is
> > > problematic:
> > >
> > > abstract AbstractNode
> > > abstract PhylogenyNode <: AbstractNode
> > > abstract NetworkNode <: AbstractNode
> > > abstract AbstractEdge
> > > abstract PhylogenyEdge <: AbstractEdge
> > > abstract NetworkEdge <: AbstractEdge
> > >
> > > type Branch{N <: PhylogenyNode} <: PhylogenyEdge
> > >
> > > from::N{Branch}
> > > to::N{Branch}
> > > length::Float64
> > >
> > > function Branch{N}(::Type{N})
> > >
> > > x = new()
> > > length!(x, -1.0)
> > > return x
> > >
> > > end
> > >
> > > end
> > >
> > > type Clade{E <: PhylogenyEdge} <: PhylogenyNode
> > >
> > > from::E
> > > to::Vector{E}
> > > confidence::Float64
> > >
> > > function Clade{E}(::Type{E})
> > >
> > > x = new()
> > > x.to = Vector{E}()
> > > confidence!(x, -1.0)
> > > return x
> > >
> > > end
> > >
> > > end
> > >
> > >
> > >
> > > As you can see both concrete types are parametric, and as a result there
> >
> > is
> >
> > > a certain circularity to it
> > > Clade{Branch{Clade{Branch{Clade{Branch}}}}}.... That ultimately ends in
> > > something like Clade{Branch{N<:PhylogenyNode}}. I'd like to know if this
> >
> > is
> >
> > > type-certain or not - the fact it terminates in N<:PhylogenyNode or
> > > E<:PhylogenyEdge makes me doubt it.