Suppose I have a module U of utility routines that are used by module A, which has my application. These are in files called u.jl and a.jl respectively. How do I include the utility routines in the application? It seems that there are at least four choices: (1) I can make a package and put U in the package, (2) I can include U from the repl, (3) I can put an include u.jl
statement in a.jl, but before the module A
declaration, (4) I can put include u.jl
inside a.jl inside the module A
declaration. In each of these cases except the first, the setting of LOAD_PATH
plays a role. In each of these cases, I need appropriate using
or import
statements. The cases behave differently when I make a change to u.jl while debugging a.jl. And possibly precompilation also matters.
Which of these solutions is the best? I’ve found my own solution which seems to be OK, but I would have trouble explaining these choices to someone else. An issue here is that the documentation on modules in the Julia manual is not as in-depth as the other sections. Could I request that a Julia developer who knows this material well write a more extensive commentary for that section of the manual?
I always make a package, and let it live in .julia/VERSION/
. Even for things that are used by a single project. When Pkg3
comes out, I will consider putting them in some other directory, but I have no strong reasons to do so (except that I need to migrate manually when a new version of Julia comes out).
Tamas,
This is a reasonable solution, although different from the one I adopted. However, just to clarify my request, I am not actually seeking a specific software design pattern. Rather, I am seeking a greater understanding of how module
, using
, and import
, LOAD_PATH
and recompilation work, and how they are intended to be used in a typical small-project environment. Like many participants in this discourse site, I teach at a university, so I need to be able to explain aspects of Julia to students even if I’m not using them.
– Steve Vavasis
1 Like
My understanding is that the current package system is under redesign:
https://github.com/JuliaLang/Juleps/blob/master/Pkg3.md
so I am not sure I would spend too much time with students on the details.
However, I am in a similar situation (will teach Julia soon), and this is what I would explain in the first pass (hopefully someone more knowledgeable will come along and fill in the details):
- Packages are a distribution channel (“files on a disk”).
Pkg
helps you manage these (update, check out branches, resolve dependencies, etc). Packages are orthogonal to modules, mostly.
-
import X
and using X
search LOAD_PATH
for module X
, and load it into the image. import X
merely makes the module name available. using X
also makes the names it exports available. import X: foo
allows you to add methods to X.foo
without prefixing, but that’s just a convenience, you can use X.foo
.
- modules are namespaces, and have nifty features such as submodules etc, pretty well explained in the docs. Namespaces are useful for organizing your code.
Regarding (re,pre)compilation: my mental model is that modules are compiled when loaded, except when they were used and precompiled before. If everything works out, I tend to think of that as a speed gain, not something that should affect things. I would perhaps not talk about this in a class unless it is specifically about programming.
The advantage of the workflow I outlined above is that
- the students don’t need to touch
LOAD_PATH
, or even know about it,
-
PkgDev.generate
will put everything in the right place, so packages are very cheap to create.