Working with Multiple Files in Julia#
Learning Objectives#
Understand how to organise Julia code across multiple
.jl
files.Use the
include()
function to load external Julia files into a program.Structure a small project by separating functionality into different files
Recognise when and why to use modules for better code organisation
Implement a basic module to manage namespaces and exports in larger projects
As your Julia projects grow larger, it’s good practice to organise your code across multiple files. Julia provides simple ways to include and reuse code from different files, allowing you to keep your code modular, maintainable, and easy to understand.
Using include()
to Combine Files#
The simplest way to bring code from another file into your current script or notebook is with the include()
function.
Suppose you have two files:
helpers.jl
:
function greet(name)
println("Hello, ", name, "!")
end
main.jl
:
include("helpers.jl")
greet("Alice")
When you run main.jl
, Julia will read and execute the code from helpers.jl
first, making the greet
function available.
Note: include()
simply inserts the code from the other file as if you had typed it into the current file.
Common Pattern:
Place helper functions in their own
.jl
file (e.g.helpers.jl
), keeping your main script focused on high-level logic.At the top of your main script, use
include("helpers.jl")
to load these helper definitions.
Example of Organising a Small Project#
File Structure:
my_project/
├── main.jl
├── setup.jl
└── game_logic.jl
setup.jl
function initialize_game()
println("Game initialized!")
end
game_logic.jl
function play_turn()
println("Turn played!")
end
main.jl
include("setup.jl")
include("game_logic.jl")
initialize_game()
play_turn()
When you run main.jl
, it will include both setup.jl
and game_logic.jl
and call their functions.
Using Modules for Larger Projects#
If you want better organisation or to avoid accidentally clashing function names, you can wrap code in a module. A module is like a self-contained package of code.
For example, MathHelpers.jl
:
module MathHelpers
export add_numbers
function add_numbers(x, y)
return x + y
end
end # module MathHelpers
main.jl
include("MathHelpers.jl")
using .MathHelpers # the dot means "from the current module"
result = add_numbers(5, 3)
println(result)
Avoiding Name Collisions with Modules#
Imagine you have two modules, each exporting a function called greet
:
# File: English.jl
module English
export greet
greet() = println("Hello!")
end
and
# File: Spanish.jl
module Spanish
export greet
greet() = println("¡Hola!")
end
In your main script, you can include and call both without conflict:
include("English.jl")
include("Spanish.jl")
using .English # import English.greet
using .Spanish # import Spanish.greet
English.greet() # prints "Hello!"
Spanish.greet() # prints "¡Hola!"
Because each greet
lives in a different module namespace, Julia treats them as entirely separate functions, avoiding accidental name collisions in large codebases.
A key part here is the leading dot in .English
, which tells Julia to “look for a module named English
in the current project rather than trying to load a registered package called English
from the environment. In effect, this restricts the lookup to relative import: “I know I just did include(“English.jl”), so load that module”, avoiding any confusion with a hypothetical package called English elsewhere.
The Main
Module#
Every Julia script or REPL session executes within a default top-level module called Main
. When you write code at the top level, whether in a .jl
file or interactively, you are defining names in Main
. Any module X
you include becomes a submodule Main.X
, and a relative using .X
refers to that. You can always refer explicitly to top-level names as Main.name
, though that’s rarely needed.
*For more on standard modules, see the Julia manual Standard Modules Page.
Note: Modules are useful when your codebase grows and you want clear namespaces, controlled exports, or later want to turn your project into a package.
Good Practice:
Keep related functions grouped together in logical files
Name your
.jl
files meaningfully (e.g.,plotting_utils.jl
,data_loader.jl
)Start small with
include()
for simple projectsAs your project grows, consider moving to modules for better organization
Exercise: Multi-File Projects#
Create two Julia files:
utilities.jl
with a functiondouble(x)
that returns2*x
main.jl
that includesutilities.jl
, and callsdouble(10)
, printing the result
Can you make it even cleaner by wrapping utilities.jl
in a module?