I am exploring the type system of Julia seriously for the first time and I got stuck with a practical problem I have in one of my packages. Suppose I have various grid types following an interface:
@doc doc"""
A data point in an `N`-dimensional space represented by
`N` scalars (a.k.a. coordinates) of type `T`, holding a
value of type `V`.
""" ->
abstract AbstractDataPoint{N,T,V}
@doc doc"""
An iterable collection of points of type `P`.
""" ->
abstract AbstractPointCollection{P}
@doc doc"""
A grid of points of type `P`.
""" ->
abstract AbstractGrid{P}
@doc doc"""
Valid representations of a spatial domain.
""" ->
AbstractDomain = Union{AbstractPointCollection,AbstractGrid}
@doc doc"""
A path in a spatial domain of type `D`.
""" ->
abstract AbstractPath{D}
In this interface, I have various representations of a spatial domain AbstractDomain
, either grids types or point collections. I would like to traverse such domains with different types of paths. For achieving this goal I tried to introduce the AbstractPath
type.
Now consider one possible implementation of the interface:
immutable DataPoint{N} <: AbstractDataPoint{N,Real,Real}
coords::NTuple{N,Real}
value::Real
end
coords(p::DataPoint) = p.coords
value(p::DataPoint) = p.value
type PointCollection{N} <: AbstractPointCollection{DataPoint{N}}
points::AbstractVector{DataPoint{N}}
end
npoints(pc::PointCollection) = length(pc.points)
type ImageGrid{N} <: AbstractGrid{DataPoint{N}}
data::AbstractArray{Real,N}
dx::Real
dy::Real
dz::Real
ImageGrid(data) = ImageGrid(data,1.,1.,1.)
end
npoints(g::ImageGrid) = prod(size(g.data))
Finally, the question. Suppose there is a natural order for traversing spatial domains. For example, an image grid is naturally traversed in column-major order, a point collection is traversed in forward order, etc. I would like to define a DefaultPath
for all AbstractDomain
:
type DefaultPath{AbstractDomain} <: AbstractPath{AbstractDomain}
# TODO
end
How would you approach this problem? Should I define a start
, next
and done
for all new types, make them part of the interface specification and then call these methods inside of the DefaultPath
? How to do that in a Julian way?
Besides the question, please feel free to give feedback on the interface, if there is anything that can be done better in terms of performance, etc.