I’m developing a package which defines a number of types. Some types are helpers and some are specific implementations (parametric or abstract) of other types from this package.
I’ve been poking around popular packages to see how they might handle this. I’ve seen different styles. I’m all about extensible patterns, so if it’s not extensible gracefully I’m a little annoyed.
The most common package looks like this: One module defining more general/generic type(s) or interface(s) and including more specific code via direct file inclusion. The “module” file exports stuff for the included files.
module Foos
export
Foo,
bar
struct Foo{T}
x::T
end
include("bar.jl")
foo(x::Foo{T}) where T = x.x+x.x
end
bar.jl
foo(x::Foo{String}) = x.x*x.x
bar() = "hey"
This is really just breaking a large Foos.jl file into multiple files. Evidence of that is that Foos.jl exports bar.jl functions/types.
To extend this pattern to include more types/interfaces in modules I’d need one package per and compose via using. If they are very small types/interfaces, I don’t know that I really want to break them up into multiple packages.
So I’ve seen this kind of pattern for multiple modules in a single package.
Foos.jl
module Foos
include("Bars.jl")
using .Bars
Problem here is I can only do that for Bars once inside Foos tree of includes. So if Foos includes Bars and Bazs, but Bars and Bazs want to both use a module Bats I get an error. This isn’t very extensible.
In my specific case Bats should really be it’s own package. However, I could see other cases where Bats was a utility module that only made sense in the Foos context. Where it should probably not be a module I suppose and just included and I trade an error for some warnings when Bats functions etc are redefined.
Seems I’m limited to linear or flat include/using relationships between files and modules in one package. Breaking packages up anytime I need to go beyond this seems the only sensible way. If I want to start off extensible that means I should always start a new package when I have a new type/interface. This seems impractical.
Any suggestions for more extensible patterns for large projects where I can have multiple modules in one package?