What’s the best practice for the management of a package and its modules?
Please take a look at the following example.
In this example, module A is a kind of a Base module, and module B is a corresponding module.
Also, I’d like to make functions accessible as MyPackage.my_func (without exporting my_func like using Reexport).
What should I do?
src/MyPackage.jl
module MyPackage
# `include("A.jl"); using .A` does not make support `MyPackage.A`.
end
src/A.jl
module A
abstract type AbstractA end
function my_func(a::AbstractA)
# do something
end
end
Now I’m taking the following way but I think it’s too confusing.
src/MyPackage.jl
module MyPackage
export AbstractA
abstract type AbstractA end
include("A.jl")
@reexport using .A
using .A: my_func # to make not exported functions accessible as `MyPackage.my_func`
include("B.jl")
@reexport using .B
end
Why would you constrain your namespace so much? I mostly have onemodule where I do include various *.jl files. This is sufficient even for medium size libraries.
One alternative is to organize your module into submodules as described in Submodules and relative paths in the Julia docs. That could give you a cleaner and easier organization.
Sorry but I didn’t understand.
Probably I’ve not figured out how to manage Julia packages.
If you don’t mind, can you give me an example in detail?
It would be much better if you apply your way to the example I wrote.
+) I prefer to manage a package by writing files for each module.
Your suggestion may be writing a whole library within a file and employing submodule-relative path methodology. Right?
module MyPackage
abstract type AbstractA end
include("A.jl")
include("B.jl")
...
export AbstractA, my_func, my_other_func
end
src/A.jl does not need to be another module, just gets included into MyPackage. Since AbstractA was declared beforeA.jl got included, you can use it:
# src/A.jl
function my_func(a::AbstractA)
# do something
end
the same goes for src/B.jl (you don’t need another module):
# src/B.jl
function my_other_func(a::AbstractA)
# do something else
end
If you write include above, the compiler sees MyPackage.jl like one larger source file, but you have the convenience to organise your functionality into several files. Just take care that types like your AbstractA are declared before being used in functions or other type declarations.
I usually have one source file like types.jl and include it first, where I declare common types, used by other source files included after that. Thus I do not need to declare types in my main module file like MyPackage.jl.
Oh, I didn’t know that declaring AbstractA before include("A.jl") makes it possible to use the type in A.jl.
It’s wonderful! Exactly I’ve found it and spent long time to understand the management of Julia package.
Also, I’ve taken a look at packages you’ve written. It makes everything clear. Thanks a lot @pbayer !
EDIT: Then, it would be very important to place include("some_files.jl") in an appropriate order.
EDIT2: For other readers who are confused like me, I would say that include("my_file.jl") will work as if the code written in my_file.jl is at the place where the include is.
hmmmmm… almost. The included file is evaluated at the global scope of the module calling it. So, if the code included declares a variable myVar, and you call include(....) within for example a for loop or a function, myVar would be in the global scope of the module, not in the local scope of the for block or of the function.