I’m new to Julia (2 weeks of exp). I would like to port and extend existing project from C++/python to julia. I’m having big difficulties in structuring my project. The project will contain roughly 50-100 files/modules, some modules will depend on other modules in the project. Coming from C++/python naturally I was expecting following layout to work out of the box:
#file ModuleA.jl
module ModuleA
...
end
#file ModuleB.jl
module ModuleB.jl
using ModuleA # or .ModuleA
...
end
To my surprise ModuleB will not import dependent ModuleA. I’ve been researching this subject for a week and haven’t found good solution. I found following options:
1. Add project directories to LOAD_PATH
Upsides:
- local modules just work ™
- push!(LOAD_PATH, …) can be added to startup file
- project startup file can be added to vscode settings
"julia.additionalArgs": "-L${workspaceFolder}/startup.jl"
Downsides:
- feels hacky
- project can’t have Project.toml, so can’t become a package
- compiled modules pollute local\share\julia\compiled\v1.9\ with dlls
- Pluto disregards
julia -Lstartup.jl
, so LOAD_PATH must be amended in every notebook
2. Use include
Include file followed by .using
#file ModuleB.jl
module ModuleB.jl
include("ModuleA.jl")
using .ModuleA
...
end
This doesn’t work when more than one dependency includes the same file due to lack of include once semantics, there is no #pragma once
or #ifdef
to my knowledge, I rate this option as worse than C.
3. FromFile
FromFile looks great at first glance
#file ModuleB.jl
module ModuleB.jl
@from "ModuleA.jl" using ModuleA
...
end
but there are a few problems:
- module are wrapped in additional modules, this changes module tree
- modules loaded into Main are wrapped differently than modules loaded from other modules so types often differ typeof(b.a) != typeof(a), potentially problematic for dispatching
- @from … using … doesn’t work in Pluto
4. Create one monolithic file
Create one main julia file per project, all files are included into the monolith:
#file ModuleB.jl
module ModuleB.jl
# no dependencies declared here
...
end
#file Monolith.jl
include("ModuleA.jl")
include("ModuleB.jl")
Only downsides:
- modules can’t declare their dependencies
- files must be included in topological order
- files/modules become just inlines, they can’t be executed/tested in julia
- worse than C, it’s not 1970 anymore
- over my dead body option
5. Create package per file/module
For each file/module create a package. Packages can be ]dev
’ed or published in local repository.
- requires nesting of every file/module into it’s own directory
- doubles the amount of files (julia + toml)
- even for a small project this will become a maintenance hell
Summary
Are there any other options that I missed?
Of all these options, I chose #1 as the least bad for now. I like the language but I feel extremely frustrated that there is no modern way to deal with local dependencies in Julia. The topic relative using/import should search current directory · Issue #4600 · JuliaLang/julia · GitHub is decade old, left unaddressed. Are there any plans to improve the situations? If not, it’s not too late for me to bail out.