Hi @ffevotte. Good question. Here’s a simple example that captures the essence of a real problem we’re having at my company: Suppose we have a MyTypes module that exports a bunch of common types. Those types are on the interface for functions in the Subsystem module. Now we want to build two separate systems that use Subsystem. Here’s an example. Suppose the modules are included from separate files (they’re just written this way so there’s a single working example file).
Here’s a system that needs to use the functionality of Subsystem directly.
module SystemA
# Included from MyTypes.jl.
module MyTypes
export Type1, Type2
struct Type1; field::Int64; end
struct Type2; field::Float64; end
end
using .MyTypes
# Included from Subsystem.jl.
module Subsystem
export f
import ..MyTypes: Type1, Type2 # This line breaks modularity!
# import ..SystemA: Type1, Type2
f(a::Type1, b::Type2) = Type2(a.field + b.field)
end
using .Subsystem
# Now for whatever this module was supposed to do.
x = f(Type1(1), Type2(2.0))
end
Here’s a different system, one that needs to use the functionality of Subsystem indirectly. [Edit: This is intended to be totally separate from SystemA, like a different program.]
module SystemB
# Included from MyTypes.jl.
module MyTypes
export Type1, Type2
struct Type1; field::Int64; end
struct Type2; field::Float64; end
end
using .MyTypes
# Included from SomeOtherSubsystem.jl.
module SomeOtherSubsystem
export g
import ..MyTypes: Type1, Type2
# import ..SystemA: Type1, Type2
# Included from Subsystem.jl.
module Subsystem
export f
import ..MyTypes: Type1, Type2 # This line breaks modularity!
# import ..SystemA: Type1, Type2
f(a::Type1, b::Type2) = Type2(a.field + b.field)
end
using .Subsystem
g(a, b) = f(Type1(b.field), Type2(a.field))
end
using .SomeOtherSubsystem
# Now for whatever this module was supposed to do.
x = g(Type1(1), Type2(2.0))
end
SystemA.x
SystemB.x
This doesn’t work. In order for Subsystem to work in the second case, its import
statement would need an extra period, because it’s deeper here. Hence no single Subsystem.jl file works in both cases.
If the import ..: Type1, Type2
syntax worked, then this type of modularity would work.
This is all part of a bigger picture that looks like this: My company needs all of this code in a single repo. We want modularity. Solutions:
- If we break things into modules like this, modules actually can’t be used in multiple contexts, so this doesn’t work.
- If we break things into local packages and
]dev
them, then there are new problems with modularity ["Unsatisfiable requirements" when local packages use local packages (fixed in v1.4)]. - If we create a local registry for our own package, that’s also problematic [ibid].
- This only working solution we’ve found is to avoid making modules and packages and just make a bunch of .jl files with functions and types in them, and then include all those files in one big module (possibly Main). This obviously has its own problems, like name conflicts and the fact that nothing can be precompiled, etc., so the startup time is now really slow.
That’s all just context to answer your question, François. This thread should still be about whether or not ..:
is useful and should be prioritized.