Content from Introduction
Last updated on 2025-07-30 | Edit this page
Overview
Questions
- “What is Julia?”
- “Why use Julia?”
Objectives
- “Explain the difference between interpreted and compiled programming languages”
- “Compare how composing works in Julia and some common programming languages”
What is a programming language?
A programming language mediates between the natural language of humans and the machine instructions of a computer. The human specifies what the computer should compute on a high level using the programming language. This specification will be translated to machine instructions, the so called assembly code, which will be executed by the processor (CPU, GPU, …).
Interpreting and compiling
This translation happens differently depending on the programming language you use. There are mainly two different techniques: compiling and interpreting. Interpreted languages such as Python and R translate instructions one at a time, while compiled languages like C and Fortran take whole documents, analyze the structure of the code, and perform optimizations before translating it to machine code.
This leads to more efficient machine instructions of the compiled code at the cost of less flexibility and more verbose code. Most prominently, compiled languages need an explicit type declaration for each variable.
Why Julia?
Julia is a programming language that superficially looks like an interpreted language and mostly behaves like one. But before each function is executed it will be compiled just in time.
Thus you get the flexibility of an interpreted language and the execution speed of a compiled language at the cost of waiting a bit longer for the first execution of any function.
There is another aspect of Julia that makes it interesting and that is the way packages compose. This is captured the best by an analogy from Sam Urmy:
Say you want a toy truck.
The Python/R solution is to look for the appropriate package–like buying a Playmobil truck. It comes pre-manufactured, well-engineered and tested, and does 95% of what you would ever want a toy truck to do.
The Fortran/C solution is to build the truck from scratch. This allows total customization and you can optimize the features and performance however you want. The downside is that it takes more time, you need woodworking skills, and might hurt yourself with the power tools.
The Julia solution is like Legos. You can get the truck kit if you want–which will require a bit more assembly than the Playmobil, but way less than building it from scratch. Or, you can get the component pieces and assemble the truck to your own specs. There’s no limit to what you can put together, and because the pieces all have the same system of bumps, everything snaps together quickly and easily.
OK, sure. Toy trucks are like linear algebra, though, a common request, and every “toy system” will have an implementation that works basically fine. But what if you want a time-traveling sailing/space ship with lasers AND dragon wings? And it should be as easy to build and use as a basic dump truck?
There’s a reason that only Lego ever made anything like Dr. Cyber’s Flying Time Vessel!
Originally posted on Discourse.
Keypoints
- “Julia is a just-in-time compiled language”
- “Julia packages compose well”
Content from Using the REPL
Last updated on 2025-08-12 | Edit this page
Overview
Questions
- “How to use the REPL?”
Objectives
- “Explore basic functionality of input.”
- “Learn how to declare variables.”
- “Learn about REPL modes.”
Entering the REPL
Melissa and her classmates open a terminal and launch
julia
:
JULIA
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.7.2 (2022-02-06)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia>
This is the so-called REPL, which stands for read-evaluate-print-loop. The interactive command-line REPL allows quick and easy execution of Julia statements.
Like the terminal, the Julia REPL has a prompt, where it awaits input:
implicit prompt
Most of the code boxes that follow do not show the
julia>
prompt, even though it’s there in the REPL.
Why?
It’s important to delineate input (what you type) and output (how the machine responds). The prompt can be confusing, so it is excluded. You may assume that any Julia box prepends the prompt on each line of input.
Visual Studio Code
An alternative to using the REPL through a terminal is to work with
Visual Studio Code or its open source altenative
VSCodium. VSC is a source code editor for which a julia
extension is available. After installing the application, simply click
on the “Extension” symbol on the left side and search for
julia
. Once installt julia
remains usable and
can be selected as a programming language in new documents.
For further guidance and visual aid, check out the provided video!
Variables
The first thing they try is to perform basic arithmetic operations:
OUTPUT
30.2
That works as expected. It is also possible to bind a name to a value
via the assignment operator =
, which makes it easier to
refer to the value later on. These names are called
variables.
OUTPUT
60.4
Melissa notices that assignment also returns the value. She can also check which variables are defined in the current session by running
OUTPUT
name size summary
–––––––––––––––– ––––––––––– –––––––
Base Module
Core Module
InteractiveUtils 270.164 KiB Module
Main Module
ans 8 bytes Float64
distance 8 bytes Float64
distance_x_2 8 bytes Float64
Unicode
In Julia, Unicode characters are also allowed as variables like
α = 2
. Unicode characters can be entered by a backslash
followed by their LaTeX
name and then pressing tab (in this case
\alpha
tab).
REPL-modes
Unfortunately Melissa can’t remember the LaTeX name of ∂ so she copies the character , presses ? for help mode,
pastes the ∂ character, then presses enter:
OUTPUT
"∂" can be typed by \partial<tab>
Great! This way she can easily look up the names she needs. She gets back to normal mode by pressing backspace.
Exploring Julia’s Help Mode
Help mode can also be used to look up the documentation for Julia
functions. Use Julia’s help mode to read the documentation for the
varinfo()
function.
Another useful mode is the shell mode that can be entered by pressing ;. The prompt has now changed:
Shell mode can be used to issue commands to the underlying shell, but don’t confuse it with an actual shell: special shell syntax like piping won’t work. Like before, hit backspace to get back to the Julia prompt.
Hello, shell>
(pwd
and cd
) !
Two commonly used shell commands are pwd
(print working
directory) and cd
(change
directory).
- Use
pwd
to find out what is your current working directory. - Type the command
cd
in shell mode, which by default will bring you to your “home directory”. - Use
pwd
again. Did you get a different result from before? Why or why not?
The working directory is the location from which you launched Julia.
To navigate to a different directory, you can use the cd
command by entering: cd <directory>
. By default, this
command will return you to your home directory if a specific directory
is not given. If you initially launched Julia from your home directory,
the working directory remains unchanged, so the output of the second
pwd
command will be identical to the first. Conversely, if
you were in a different directory when you started Julia, the results of
the two pwd
commands will differ. You can use
cd -
to go back to your previous location.
Hello, shell>
(ls
)!
Another useful shell command is ls
(list
files). Use it to show the contents of your home directory.
Hello, shell>
(nano
and cat
)!
Use the shell mode to create a file called hello.jl
with
the nano terminal text editor. Inside that file write the simple hello
world program print("Hello World!")
.
Check the content of the file using cat hello.jl
and
then run the program using julia hello.jl
.
Finally there is package mode that is entered with ] which is used for package management, which will be covered later on:
To exit shell, help or pkg mode, hit backspace.
Keypoints
- “The REPL reads the given input, evaluates the given expression and prints the resulting output to the user.”
- “Pressing ? enters help mode.”
- “Pressing ; enters shell mode.”
- “Pressing ] enters pkg mode.”
Content from The Julia Type System
Last updated on 2025-08-12 | Edit this page
Overview
Questions
- “What is the use of types?”
- “How are types organized in Julia?”
Objectives
- “Understand the structure of the type tree.”
- “Know how to traverse the type tree.”
- “Know how to build mutable and immutable types.”
Structuring variables
Melissa wants to keep the variables corresponding to the trebuchet
(counterweight
, release_angle
) separate from
the variables coming from the environment (wind
,
target_distance
). That is why she chooses to group them
together using structures. There are two structure types:
- immutable structures, whose fields can not be changed after creation
- keyword:
struct
- mutable structures, whose fields can change after creation
- keyword:
mutable struct
Since Melissa wants to change the parameters of the trebuchet, she
uses a mutable struct
for it. But she cannot influence the
environment and thus uses a struct
for those values.
Types and hierarchy
Here ::Float64
is a type specification, indicating that
this variable should be a 64-bit floating point number, and
::
is an operator that is read
“is an instance of.” If Melissa hadn’t specified the type, the variables
would have the type Any
by default.
In Julia every type can have only one supertype, so let’s count how
many types are between Float64
and Any
:
1.
OUTPUT
AbstractFloat
2.
OUTPUT
Real
3.
OUTPUT
Number
4.
OUTPUT
Any
So we have the relationship
Float64 <: AbstractFloat <: Real <: Number <: Any
where <:
is the subtype operator, used here to mean the item on the
left “is a subtype of” the item on the right.
Float64
is a concrete type, which means that
you can actually create objects of this type. For example
1.0
is an object of type Float64
. We can check
this at the REPL using either (or both) the typeof
function
or the isa
operator:
OUTPUT
Float64
or
OUTPUT
true
All the other types are abstract types that are used to
address groups of types. For example, if we declare a variable as
a::Real
then it can be bound to any value that is a subtype
of Real
.
Let’s quickly check what are all the subtypes of
Real
:
OUTPUT
4-element Vector{Any}:
AbstractFloat
AbstractIrrational
Integer
Rational
This way the types form a tree with abstract types on the nodes and
concrete types as leaves. Have a look at this visualization of all
subtypes of Number
:
The correct answer is 4: while 1
is an integer,
1.0
is a floating-point value.
Instances
So far Melissa only defined the layout of her new types
Trebuchet
and Environment
. To actually create
a value of this type she has to call the so called constructor,
which is a function with the same name as the corresponding type and as
many arguments as there are fields.
OUTPUT
Trebuchet(500.0, 0.7853981633974483)
Note, how the values will get converted to the specified field type.
OUTPUT
Environment(5.0, 100.0)
trebuchet
is being called an instance or
object of the type Trebuchet
. There can only ever
be one definition of the type Trebuchet
but you can create
many instances of that type with different values for its fields.
Creating a subtype
A concrete type can be made a subtype of an abstract type with the
subtype operator <:
. Since
Trebuchet
contains several fields that are mutable Melissa
thinks it is a good idea to make it a subtype of
AbstractVector
.
Caveat: Redefining Structs
JULIA
mutable struct Trebuchet <: AbstractVector{Float64}
counterweight::Float64
release_angle::Float64
end
ERROR
ERROR: invalid redefinition of constant Trebuchet
Stacktrace:
[1] top-level scope
@ REPL[9]:1
This error message is clear: you’re not allowed to define a
struct
using a name that’s already in use.
Melissa decides to keep going and come back to this later.
Keypoints
- “In Julia types have only one direct supertype.”
Content from Using the Package Manager
Last updated on 2025-08-12 | Edit this page
Overview
Questions
- “Where do I find packages?”
- “How do I add packages?”
- “How can I use packages?”
Objectives
- “Learn to add packages using pkg-mode”
- “Learn to resolve name conflicts”
- “Learn to activate environments”
The package manager
The package Manager
This chapter focuses on the package mode available within the REPL.
A different aproach would be using the Pkg notation.
If you prefer to use that method and want to know more, remember how to get help.
(for exp. ?Pkg.add)
Now it is time for Melissa and their mates to simulate the launch of
the trebuchet. The necessary equations are really complicated, but an
investigation on JuliaHub revealed
that someone already implemented these and published it as the Julia
package Trebuchet.jl
.
That saves some real work.
Melissa enters package mode by pressing ]:
The julia>
prompt becomes a blue pkg>
prompt that shows the Julia version that Melissa is running.
After consulting the documentation she knows that the prompt is showing the currently activated environment and that this is the global environment that is activated by default.
However, she doesn’t want to clutter the global environment when
working on her project. The default global environment is indicated with
(@v1.x)
before the pkg>
prompt, where
x
is the minor version number of julia, so on julia 1.7 it
will look like (@v1.7)
. To create a new environment she
uses the activate
function of the package manager:
Activating project at `~/projects/trebuchet`
In this environment she adds the Trebuchet
package from
its open source code repository on GitHub
by typing
Melissa quickly recognizes that far more packages are being installed
than just Trebuchet
. These are the dependencies of
Trebuchet
. From the output
OUTPUT
[...]
Updating `[...]/projects/trebuchet/Project.toml`
[98b73d46] + Trebuchet v0.2.1
Updating `[...]/projects/trebuchet/Manifest.toml`
[1520ce14] + AbstractTrees v0.3.3
[79e6a3ab] + Adapt v1.1.0
[...]
she sees that two files were created: Project.toml
and
Manifest.toml
.
The project file Project.toml
only contains the packages
needed for her project, while the manifest file
Manifest.toml
records the direct and indirect dependencies
as well as their current version, thus providing a fully reproducible
record of the code that is actually executed. “That is really handy when
I want to share my work with the others,” thinks Melissa.
After the installation finished she can check the packages present in her environment.
Status `~/projects/trebuchet/Project.toml`
[f6369f11] ForwardDiff v0.10.38
[295af30f] Revise v3.6.3
[98b73d46] Trebuchet v0.2.2
Why use GitHub?
Melissa could have added the GitHub version of Trebuchet.jl by typing
In this case the JuliaHub version is the same as the GitHub version, so Melissa does not need to specify the installation.
If you know a package is stable, go ahead and install the default version registered on JuliaHub. Otherwise, it’s good to check how different that version is from the current state of the software project. Click through the link under “Repository” on the JuliaHub package page.
deactivate
does not exist, instead …
Melissa can get back to the global environment using
activate
without any parameters. Note, that any packages
that were loaded in the old environment are still loaded in the new
environment.
Using and importing packages
Now that Melissa added the package to her environment, she needs to
load it. Julia provides two keywords for loading packages:
using
and import
.
The difference is that import
brings only the name of
the package into the namespace and then all functions in that package
need the name in front (prefixed). But packages can define a list of
function names to export, which means the functions should be brought
into the user’s namespace when he loads the package with
using
. This makes working at the REPL more convenient.
Name conflicts
It may happen that name conflicts arise. For example Melissa defined
a structure named Trebuchet
, but the package she added to
the environment is also named Trebuchet
. Now she would get
an error if she tried to import
/using
it
directly. One solution is to assign a nickname or alias to the package
upon import
using the keyword as
:
Keypoints
- “Find packages on JuliaHub”
- “add packages using
pkg> add
” - “use many small environments rather than one big environment”