Well, I’m sorry to derail this further but, on the other hand, I feel like this proposal is more likely to be prioritized if people understand why it is so useful to you.
One problem I see with the way you do things, is that the same code is included in several different contexts, creating types (Type1 and Type2) and functions (f) that should be the same, but actually are not. To be clear: in what you describe above, SystemA.MyTypes.Type1 and SystemB.MyTypes.Type1 are two different types that happen to have the same structure. I would say that this could cause unexpected behavior later on, especially if these types are supposed to be part of a common interface.
Here is how I would structure things:
# Only one MyTypes module
module MyTypes
export Type1
struct Type1; field::Int; end
end
# Only one SubSystem module
module SubSystem
using ..MyTypes
export foo
foo(x::Type1) = x.field
end
# Module SystemA uses the top-level MyType module
module SystemA
using ..MyTypes
using ..SubSystem
test() = foo(Type1(1))
end
module SystemB
# This makes MyTypes and SubSystem available in the current namespace
# ...and therefore also in submodules, using the .. syntax
import ..MyTypes
import ..SubSystem
# Submodules of SystemB can also use the same top-level MyType module
# without having to know about their depth in the module hierarchy
module SomeOtherSubSystem
using ..MyTypes
using ..SubSystem
export bar
bar(x::Type1) = 2*foo(x)
end
using ..MyTypes
using .SomeOtherSubSystem
test() = bar(Type1(1))
end
SystemA.test() # --> 1
SystemB.test() # --> 2
Now, I would even go one step further and imagine that everything is in its own package. In a real application, the code base should reside in a package, that defines a top-level module of the same name. When the package environment is activated, this top-level module can be referred to in absolute syntax (without leading dots) from anywhere. Therefore, submodules can also be accessed to using an absolute path starting from the top-level module.
The following example is designed to run in the REPL, where everything is defined in the Main module. If you want to transpose it to a project, simply replace every occurrence of Main with the name of the top-level module:
# Only one MyTypes module
module MyTypes
export Type1
struct Type1; field::Int; end
end
module SubSystem
# Refer to MyTypes using an absolute path starting with the top-level module
# (replace Main with the name of your top-level module, i.e. the name of the package)
using Main.MyTypes
export foo
foo(x::Type1) = x.field
end
module SystemA
using Main.MyTypes
using Main.SubSystem
test() = foo(Type1(1))
end
module SystemB
module SomeOtherSubSystem
# No need to know how deep we are, since we now use absolute module paths
using Main.MyTypes
using Main.SubSystem
export bar
bar(x::Type1) = 2*foo(x)
end
using Main.MyTypes
using .SomeOtherSubSystem
test() = bar(Type1(1))
end
SystemA.test() # --> 1
SystemB.test() # --> 2
Again, this has almost nothing to do with your proposed syntax and I’m sorry for the thread derailment, but would such a structure make sense in your project?