Best way to structure Julia code

Dear all,
I am a bit sad that it was told here on the forum that adding a custom directory to the package search path would be depreciated.

If I write a Julia program I would like to structure it by using a module for each separate piece of code. But I want to have all my code in one git repository, and not one repo for each module.

Should every module be a package that lives in a separate repo? I think that would be stupid, because it causes lots of unnecessary overhead.

What do you think?

Uwe

2 Likes

Is there anything wrong with having one module per file, and storing all the files in the SRC folder?

1 Like

This is what I would also like to continue to do, but it is not (yet) supported by the linter of vs-code, and Kristoffer Carlsson says:

Hey @ufechner7, I agree with you. Just to be clear though, you can still break your code into modules; you’ll just need to know “where” the module is loaded. (e…g, using ..MyModuleThatTheParentModuleLoadedAlready). Since that’s not convenient for me (the reason mentioned in the post you linked), I’m no longer breaking my code into modules but rather just into a bunch of different files, and I include all of those files within the same module. Basically, I have one module: MyEntireProject, and it loads all of the necessary functions. There are certainly things about this approach that don’t work (maybe you don’t have just one big project but several), but for my big project anyway, everything kind of depends on everything else anyway, so it is working for me. Just my 2 cents on getting stuff working while hoping for a better way.

It is supported when you include the files which doesn’t need any change to LOAD_PATH. A module is just a namespace, there can be multiple modules in one file or one module spread out over other files.

1 Like

Well, I don’t think that precompilation of modules works if you include them. Correct me if I am wrong.
In addition exported type definitions of a module are not visible if the module is included, but are visible if it is used by "using ".

They are precompiled together with the toplevel module when it is loaded.

You do

include("MyModule.jl")
using .MyModule
4 Likes

Thanks for your suggestion:

It seams to work.

But it looks like an ugly workaround for me.

You need two lines, one to say where the module is and one to import it (with using or import etc.). That’s not much different from one line to modify the load path and another to import the module, so I really don’t see the problem.

4 Likes

You need to type the module name twice. And once with file name extension, brackets and quotes and once without all of this, but with a leading dot. Why is this simple task so complicated? In a good programming language simple tasks are simple. And this is not even documented in the manual.

No, you need to type the file where the module exist. There could be multiple modules in that file.

It seems you want something like https://github.com/JuliaLang/julia/issues/4600.

This comes of as kinda obnoxious.

2 Likes

Thanks for providing a reference to the relevant issue. It would be nice if a solution would be implemented.

If I understand correctly, the following will be the case after the option to add to the search path is eliminated: The only way to benefit from precompilation of a local module is to dev it. Otherwise, one has to use the include method described above, and the module is recompiled.

This raises the following concern for me. My linux environment where I use Julia has no internet connection. Because of this, I am not able to use dev. Consequently, I have no option to get the speed gain associated with module precompilation.

Is this correct, or is there a solution for this situation?

Well, if you add the current directory to the module search path:

push!(LOAD_PATH, pwd())

and the use:

using <modulename>

then precompilation works. Only the vscode linter chokes, until the issue https://github.com/julia-vscode/julia-vscode/issues/307 is fixed.

What do you mean? Devving a path doesn’t require any internet connection.

1 Like

The structure that I use (and I think hasn’t yet been mentioned here) is having each module be a submodule of the global module associated to your project/package.

Submodules can use or import one another, provided that they provide either the correct relative path (with the right number of leading dots, which I find cumbersome) or an absolute path starting with the global module.

So something like this works (assuming you are in a project named “Top”):

module Top

# Potentially in a "A.jl" file
module A
export a
a() = "OK"
end


# Potentially in a "B.jl" file
module B
using Top.A
export b
b() = a()
end



using .B
export check
check() = b()


end # module

As already mentioned, this organization in top module + submodules is orthogonal to the organization of source files: using adequately placed includes, each submodule could be in its own file, or split in separate files, or all submodules could be grouped in one file.

As far as I know, everything works well with such a setup, including Revise, precompilation and so on.

6 Likes

Thanks. I misinterpreted your initial post as meaning that this option would no longer be available. Apart from the vscode issue, this does work indeed.

You are correct. Perhaps this was an issue in the past (<v1.1); I tried again today and it works now. I had an other issue but this is related to write permissions to the environment folder. I could work around that by copying the Project/Manifest files to a dir where I do have write permissions, activate that environment and then dev my project.