How to organise files and modules?

Hello.

I’m currently using Julia for the first time in a project of more than one file and I’m struggling with module, using and include.

For this example, let say that I have a few files :

big.jl
small1.jl
small2.jl
small3.jl

In small3.jl I have some functions that I would like to use in the 3 others files. In big.jl I would like use some functions from the 3 small files. Also, in big.jl I created a module :

module Big
include("small1.jl")
include("small2.jl")
include("small3.jl")
... other stuff
end

Since we are collaborating on that project, we found it important to be able to read and understand easily the codes. So, we would like to be able to know where each functions are defined.

For example, in small1.jl and small2.jl I would like to be able to call functions from small3.jl as small3.foo(...) or something similar.

We can do that by putting everything in small3.jl into a module. But, then if I included small3.jl in small1.jl, small2.jl and big.jl I got some warning telling me that the module in small3.jl have been included more than once when I included big.jl.

The other way that we found is to only include small3.jl in big.jl and not in the two others files. Since both small1.jl and small2.jl are included in big.jl we can call big.small3.foo(...) in those file. But, it’s not exactly what I wanted first. The other problem is that if I create a new module that used big than it looks like I need to call the function like this other.big.small3.foo(...) in small1.jl and small2.jl.

Finally, my question is : What is the Julia way to do that kind of thing?

Thanks!

It’s best to think of include as copy-pasting source code into the location from which include is called. Therefore, if small2.jl calls functions from small1.jl you can simply put include statements in Big like you have above, without putting include statements in any of the small files. I think that should answer your question, but perhaps I misunderstood it.

1 Like

It is a good solution except that I cannot call functions as small3.foo(...)in small1.jl which I want to be able to do. I find the code easier to read when I can easily track where functions have been defined.

Well, I think I want to be able to do that … unless, maybe, that’s not the Julia way to work.

I think ppl normally have a base file and put the include(“base.jl”) first.

I would say that it is somehow “un-Julian” to excessively segregate functions into lots of different modules. From your desire to do small3.foo(...) I’m guessing that you are coming from Python which segregates functions in a rather extreme way. I suggest that in the long run you will be much happier if you give up on this notion. One of the big revelations I had when I started using Julia was how much the (arbitrary) association of functions with classes was damaging my ability to reason about code.

However, if you don’t want to do this, you are indeed free to define arbitrarily many nested or parallel modules.

2 Likes

So I guess it’s time to throw those Python habits of mine …

Thank for the answers.

To be fair, I think @maxtremblay35’s example rather shows an association of functions with namespaces, which is (generally) not arbitrary and quite useful in large codebases.

6 Likes

I’ve been monkeying around with a package that tries to standardize file/module setup.

Maybe you want to check it out?

https://github.com/djsegal/Julz.jl

// an example project buit with it can be found at: git.io/tokamak

Julia has support for that, see @edit, and also the frame number + Ctrl-Q functionality after a stacktrace in the REPL. Other than that, your editor should be able to help you find things quickly (eg helm in Emacs).

Given a decent editor which you know how to use, I would put modules with <300 LOC in a single file, and break up larger ones into smaller files when meaningful. However, establishing a 1:1 mapping between small files and modules is usually not productive.