A brief introduction to Julia, its installation, and how to use it.
Published
April 23, 2025
Installation
Linux and macOS:
curl-fsSL https://install.julialang.org |sh
Windows
winget install julia -s msstore
How to use Julia
there are several ways to use Julia, including the REPL, Jupyter notebooks, and various IDEs like VS Code.
REPL
The Julia REPL (Read-Eval-Print Loop) is an interactive command-line interface that allows you to execute Julia commands and scripts. To start the Julia REPL, simply type julia in your terminal after installation. You can then execute Julia commands interactively.
You can write Julia code in .jl files and run them from the REPL or command line. For example, create a file named hello.jl:
println("Hello, World!")
$ julia hello.jlHello, World!
Jupyter Notebooks
Jupyter notebooks allow you to write and execute Julia code in an interactive environment. You can install the Julia kernel for Jupyter by running:
usingPkgPkg.add("IJulia")
Hello World
println("Hello, World!") # in just one linelet# create a local scope var::String ="Hello, World!"# assigning to a variable@show var # using @show macrodisplay(var) # using display functionend
Hello, World!
var = "Hello, World!"
"Hello, World!"
Find Primes
Let’s write a simple function to check if a number is prime:
let# Define a function to check if a number is primefunctionis_prime(n::Int) ::Bool# Check if n ∈ ℕ@assert(n ≥0)# m is the last possible divider m::Int =floor(√n)# check any possible dividersfor i ∈2:m# check if n is divisable by iifis_prime(i) &&mod(n,i) ==0# return false if n is divisable by ireturnfalseendend# return true after checking that n was not divisable by any i ∈ 2:mreturntrueend@showis_prime(6)@showis_prime(7)@showis_prime(97)end# return nothing to avoid printing the last resultnothing
now let’s write a simple program to find prime numbers up to a given limit.
letfunctionfind_all_primes_till(n::Int) ::Vector{Int}# check if n ∈ ℕ@assert(n ≥0)# init the vector primes::Vector{Int} = []# check all numbers till nfor i ∈2:n# check if the it is divisable by any prime lower prime isDivisable::Bool =false m::Int =floor(√i)for p ∈ primesif p > mbreakelseifmod(i,p) ==0 isDivisable =truebreakendendif !isDivisablepush!(primes, i)endendreturn primesend@showfind_all_primes_till(100)end; nothing# return nothing inside the cell
first you need to install the pachage for plotting
importPkg# import the pachage managerPkg.add("Plots") # install the package for plotting
then you can use the package:
let# importing the Plots packageimportPlots# create a range of numbers between -4 and 4 x =-4:0.1:4# @show is a macro that prints the name and the value of a variable@showtypeof(x) # this will show that x is a range@show x # this will print x# create a vector of sine values for the range of numbers y =sin.(x) # note the . operator for element-wise operation@showtypeof(y) # this will show that y is a vector@show y[1:3] # this will print the first three values of y# plot the sine function plot = Plots.plot(x, y, label="sin(x)", title="Sine Function", xlabel="x", ylabel="sin(x)", linewidth=3)@showtypeof(plot) # this will show that plot is a Plots.Plot objectdisplay(plot) # display the plot in the notebook or Julia REPLend
Julia has two types of Datatypes: mutable and immutable. Mutable structs can be modified after creation, while immutable structs cannot.
let# mutable structs can be modifiedmutable struct Vec2 x::Float64 y::Float64end# immutable structs cannot be modifiedstruct Point2 x::Float64 y::Float64end# creating an instance of Vec2 vec =Vec2(1.0, 2.0)# creating an instance of Point2 point =Point2(3.0, 4.0)# mutable structs can be modified within functions, but can not be reassigned!# immutable structs are not allowed to be modified! That will throw an error!# as a convetion ! is used to indicate that the function modifies its argumentfunctionadd1y!(v)::Nothing v.y +=1.0 v =Vec2(0, 0) # this reassignment will not affect the original instancereturnnothingend# all base types are mutable, but reassigning them will not affect the originaladd1(x::Integer)::Integer = x +=1 x =55 y =add1(x)@show x # this will show that x is still 55@show y # this will show that y is 56add1y!(vec) # this will modify the y value of v@show vec # this will show the modified Vec2 instancetryadd1y!(point) # this will throw an error because Point2 is immutablecatche@showe# this will show the error messageendend; nothing# this is just to suppress the output of the cell
x = 55
y = 56
vec = Vec2(1.0, 3.0)
e = ErrorException("setfield!: immutable struct of type Point2 cannot be changed")
Generic structs
You can create generic structs in Julia that can hold any type of data. This is useful for creating data structures that can work with different types.
Example: Rational Number
let# creat a rational struct that is a subtype of Realmutable structRational{T <: Integer} <: Real num::T den::T# constructorfunctionRational(num::T, den::T) where T <: Integerif den ==0throw(ArgumentError("Denominator cannot be zero"))endnew{T}(num, den)endend# define a conversion method to convert Rational to Float64Base.convert(::Type{Float64}, r::Rational) =Float64(r.num) /Float64(r.den) a =Rational(1, 2) # create an instance of Rational@show a # this will show the Rational instance b::Float64 = a # convert Rational to Float64@show b # this will show the converted Float64 valueend; nothing# display nothing
a = Rational{Int64}(1, 2)
b = 0.5
Example: StaticArray
let# create a static vector type that is a subtype of AbstractVectormutable struct StaticVector{T <: Any, N} <: AbstractVector{T} data::Vector{T} # store data in a vector# constructor to ensure the length matches NfunctionStaticVector{T,N}(data::Vector{T}) where {T,N}length(data)==N ||throw(ArgumentError("Data length must be $N, got $(length(data))"))new(data)endend# implement the AbstractVector interface# length of the static vector is NBase.length(::StaticVector{T,N}) where {T,N} = N# indexingBase.getindex(sv::StaticVector{T,N}, i::Int) where {T,N} = sv.data[i]# setting values at a specific indexBase.setindex!(sv::StaticVector{T,N}, v, i::Int) where {T,N} = (sv.data[i]=v)# defining the index style for StaticVectorBase.IndexStyle(::Type{<:StaticVector}) =IndexStyle(Vector)# size of the static vector is (N,)Base.size(::StaticVector{T,N}) where {T,N} = (N,)# outer constructor to infer N from dataStaticVector(data::Vector{T}) where T =StaticVector{T,length(data)}(data)# usage staticVector =StaticVector([1, 2, 3])@show staticVectorprintln(staticVector[3])end; nothing# display nothing