module moduleA
function f1()
println("test")
end
end
module moduleB
function f2()
moduleA.f1()
end
end
moduleB.f2()
but it turned out ERROR: UndefVarError: `moduleA` not defined
I found that I can solve this problem via
module moduleB
using ..moduleA
function f2()
moduleA.f1()
end
end
However, I am not sure about the mechanism behind it, and what if I have many modules like moduleB which need to import moduleA, is there any convenient way to import the moduleA in every moduleB ?
If the inconvenience of merely adding the line using ..ModuleA to the code of your other modules seems significant, that would suggest (to me) that they don’t contain enough functionality to warrant the use of separate modules and you might be better served by sticking to just a single top-level module.
For a less general answer it might be helpful to share a little more about what your trying to achieve.
The fundamental purpose of modules is to isolate sets of names from each other like this, in other words modules are namespaces. Imports are how different modules share names with each other (in the case of packages, the first import in a session also irreversibly loads package code, then the following imports just share names again). In a typical module block, the only automatic import you have is using Base, and you’ll need to do every other import manually. If you don’t want to do that, then you probably don’t want separate modules.
You might still be wondering; why can’t modules just automatically import their own names in each other? After all, the other names in the module are still isolated, so shouldn’t that be close enough? That can’t happen because namespaces also isolate distinct names with the same symbols, so without imports, a Cells.differentiate is completely different from Calculus.differentiate. To evade the error in your example another way, I can make an entirely separate module also named moduleA nested inside moduleB to execute different code:
julia> module moduleB
module moduleA
function f1()
println("the wrong one")
end
end
function f2()
moduleA.f1()
end
end
Main.moduleB
julia> moduleB.f2()
the wrong one
julia> moduleA.f1()
test
julia> moduleA === moduleB.moduleA
false
Python modules do namespacing the same way. The only significant differences are the import syntax and that modules are created per file instead of a syntax block. If you had a moduleA.py file and a moduleB.py file, the latter would need a from . import moduleA statement to work too.