Getting started
Introduction
Julia is a high-performance dynamic language for scientific computing with multiple dispatch and a sophisticated type system.
Installation
# Download from julialang.org
# Or use juliaup (recommended)
curl -fsSL https://install.julialang.org | sh
Hello World
println("Hello, World!")
# Variables (dynamically typed)
x = 10
name = "Julia"
# Type annotations (optional)
y::Int64 = 42
z::Float64 = 3.14
REPL Quick Start
# Enter REPL by running `julia`
# Shell mode (type ;)
julia> ;
shell> ls
# Package mode (type ])
julia> ]
pkg> add DataFrames
# Help mode (type ?)
julia> ?
help?> println
# Back to Julia mode (backspace)
Basic Syntax
Variables & Types
# Assignment
x = 10
y = 2.5
# Multiple assignment
a, b, c = 1, 2, 3
# Type annotations
function foo(x::Int)::String
return "Got: $x"
end
# Type assertion
x = 10::Int
Strings
# String literals
s = "Hello"
c = 'x' # Character
# Interpolation
name = "World"
"Hello, $name"
"1 + 2 = $(1 + 2)"
# Triple-quoted strings
text = """
Multi-line
string
"""
# Concatenation
"Hello" * " " * "World"
string("Hello", " ", "World")
Numbers
# Integers
x = 1
y = 0x1F # Hex
z = 0b1010 # Binary
# Floats
a = 1.0
b = 1e10
c = 2.5e-4
# Rational numbers
r = 1//2 # 1/2
3//6 == 1//2 # true
# Complex numbers
c = 1 + 2im
Arrays & Collections
Arrays (1-indexed ⚠️)
# Create arrays
arr = [1, 2, 3, 4]
arr2d = [1 2 3; 4 5 6] # 2×3 matrix
# Indexing (1-based!)
arr[1] # First element
arr[end] # Last element
arr[2:4] # Slice [2, 3, 4]
# Comprehensions
[x^2 for x in 1:10]
[x*y for x in 1:3, y in 1:3]
# Type specification
Float64[1, 2, 3]
Array Operations
# Common functions
length(arr) # Number of elements
size(arr) # Dimensions
push!(arr, 5) # Append (mutates!)
pop!(arr) # Remove last
append!(a, b) # Extend array
# Concatenation
vcat(a, b) # Vertical [a; b]
hcat(a, b) # Horizontal [a b]
[a; b] # Vertical
[a b] # Horizontal
Broadcasting
# Element-wise operations
arr .+ 10 # Add 10 to each
arr .* 2 # Multiply each by 2
arr .^ 2 # Square each
# Broadcasting functions
sin.(arr)
f.(arr) # Apply f to each
# Multiple arrays
a .+ b # Element-wise add
a .* b # Element-wise multiply
Other Collections
# Tuples (immutable)
t = (1, 2, 3)
t = 1, 2, 3 # Same
t[1] # Access: 1
# Named tuples
nt = (x=1, y=2)
nt.x # Access: 1
# Dictionaries
d = Dict("a" => 1, "b" => 2)
d["a"] # Get value
d["c"] = 3 # Set value
# Sets
s = Set([1, 2, 3])
push!(s, 4)
Control Flow
Conditionals
# If statements
if x > 0
println("positive")
elseif x < 0
println("negative")
else
println("zero")
end
# Ternary operator
result = x > 0 ? "pos" : "neg"
# Short-circuit evaluation
x > 0 && println("positive")
x == 0 || println("non-zero")
Loops
# For loops
for i in 1:5
println(i)
end
for i = 1:5 # Same
println(i)
end
# Multiple variables
for i in 1:3, j in 1:2
println(i, j)
end
# While loops
while x < 10
x += 1
end
# Break and continue
for i in 1:10
i == 5 && break
i % 2 == 0 && continue
println(i)
end
Functions
Basic Functions
# Long form
function greet(name)
return "Hello, $name"
end
# Short form
greet(name) = "Hello, $name"
# Anonymous functions
x -> x^2
(x, y) -> x + y
# Multiple return values
function minmax(x, y)
return min(x, y), max(x, y)
end
a, b = minmax(3, 5)
Arguments
# Optional arguments
function power(x, n=2)
return x^n
end
power(3) # 9
power(3, 3) # 27
# Keyword arguments
function plot(x, y; style="solid", color="blue")
# ...
end
plot(x, y, color="red")
# Varargs
function sum_all(args...)
return sum(args)
end
sum_all(1, 2, 3) # 6
Multiple Dispatch
# Same function name, different types
f(x::Int) = "integer"
f(x::Float64) = "float"
f(x::String) = "string"
f(1) # "integer"
f(1.0) # "float"
f("hi") # "string"
# Multiple arguments
g(x::Int, y::Int) = x + y
g(x::String, y::String) = x * y
# Check methods
methods(f)
Types & Structs
Type System
# Abstract types
abstract type Animal end
abstract type Pet <: Animal end
# Concrete types (immutable)
struct Point
x::Float64
y::Float64
end
# Mutable structs
mutable struct Person
name::String
age::Int
end
# Usage
p = Point(1.0, 2.0)
person = Person("Alice", 30)
person.age = 31 # OK (mutable)
Parametric Types
# Generic types
struct Container{T}
value::T
end
# Usage
c1 = Container{Int}(42)
c2 = Container{String}("hello")
c3 = Container(3.14) # Auto-inferred
# Type constraints
struct Pair{T<:Number}
a::T
b::T
end
Type Operations
# Type checking
typeof(x) # Get type
x isa Int # Check type
Int <: Number # Subtype check
# Type conversion
convert(Int, 3.14)
Int(3.14) # Error if not exact
parse(Int, "42")
# Type union
Union{Int, String}
Modules & Packages
Modules
# Define module
module MyModule
export foo, bar
foo() = "exported"
bar() = "exported"
baz() = "not exported"
end
# Using modules
using MyModule # Import exports
MyModule.baz() # Access non-exported
import MyModule
MyModule.foo()
import MyModule: foo # Import specific
Package Management
# Enter package mode (])
] add DataFrames # Install package
] rm DataFrames # Remove
] update # Update all
] status # List installed
# In code
using Pkg
Pkg.add("DataFrames")
Pkg.update()
Pkg.status()
# Using packages
using DataFrames
import CSV
Performance Tips
Type Stability
# ❌ Type-unstable (slow)
function bad(n)
x = 1
for i in 1:n
x = x / 2 # Int -> Float64
end
return x
end
# ✅ Type-stable (fast)
function good(n)
x = 1.0 # Start as Float64
for i in 1:n
x = x / 2
end
return x
end
# Check with @code_warntype
@code_warntype bad(10)
Vectorization
# ❌ Slow (allocates intermediate arrays)
result = sin(cos(x)) .+ 3
# ✅ Fast (fused, one allocation)
result = @. sin(cos(x)) + 3
result = sin.(cos.(x)) .+ 3 # Same
# Avoid in-place when possible
x .= x .+ 1 # In-place update
Performance Annotations
# Inline hints
@inline small_function(x) = x^2
@noinline large_function(x) = # ...
# Bounds checking
@inbounds arr[i] # Skip bounds check
# SIMD
@simd for i in 1:n
arr[i] = i^2
end
# Timing
@time func() # Time once
@btime func() # Benchmark (BenchmarkTools)
Memory Tips
# Pre-allocate arrays
arr = Vector{Float64}(undef, n)
arr = zeros(Float64, n)
# Avoid global variables
const CONST_VAL = 10 # Use const
# Use views instead of copies
view(arr, 1:10)
@view arr[1:10]
arr[1:10] # Creates copy
Metaprogramming
Expressions
# Create expressions
ex = :(x + y)
ex = quote
x = 1
y = 2
x + y
end
# Inspect
dump(ex)
Meta.show_sexpr(ex)
# Interpolation
a = :x
:($a + $a) # :(x + x)
Macros
# Define macro
macro sayhello(name)
return :( println("Hello, ", $name) )
end
# Use macro
@sayhello "World"
# Built-in useful macros
@time expr # Time execution
@elapsed expr # Return time
@show x # Print x = value
@assert cond # Assert condition
Common Patterns
File I/O
# Read file
text = read("file.txt", String)
lines = readlines("file.txt")
# Write file
write("out.txt", "content")
# Open/close
open("file.txt", "r") do file
for line in eachline(file)
println(line)
end
end
Error Handling
# Try-catch
try
result = risky_operation()
catch e
println("Error: $e")
finally
cleanup()
end
# Throw errors
error("Something went wrong")
throw(DomainError(x, "must be positive"))
# Define errors
struct MyError <: Exception
msg::String
end
List Comprehensions
# Array comprehension
[x^2 for x in 1:10]
[x for x in 1:10 if x % 2 == 0]
# Generator (lazy)
sum(x^2 for x in 1:10)
# Multi-dimensional
[x*y for x in 1:3, y in 1:3]
# Nested
[i+j for i in 1:3 for j in 1:2]
REPL & Debugging
REPL Modes
# Julia mode (default)
julia> 1 + 1
# Help mode (?)
help?> println
# Shell mode (;)
shell> ls -la
# Package mode (])
pkg> add DataFrames
# Search mode (Ctrl+R)
# Up/Down arrows for history
Debugging Tools
# Basic debugging
@show x # Print x = value
println("x = $x")
dump(obj) # Show structure
# Profiling
@time func() # Time + allocations
@allocated func() # Memory only
@profile func() # Detailed profile
# Code introspection
@code_lowered func(args)
@code_typed func(args)
@code_llvm func(args)
@code_native func(args)
Gotchas
1-Based Indexing ⚠️
arr = [1, 2, 3]
arr[1] # First element (not arr[0]!)
arr[end] # Last element
arr[0] # BoundsError
# Use eachindex for iteration
for i in eachindex(arr)
println(arr[i])
end
Copy vs Reference
# Arrays are passed by reference
a = [1, 2, 3]
b = a # b points to same array
b[1] = 99
a[1] # 99 ⚠️
# Make a copy
b = copy(a)
b = a[:] # Also works
# Deep copy for nested structures
c = deepcopy(a)
Mutation Conventions
# Functions ending in ! modify arguments
sort(arr) # Returns sorted copy
sort!(arr) # Modifies arr in place
push!(arr, x) # Mutates
append!(a, b) # Mutates
filter!(f, arr) # Mutates
Global Scope
# ❌ Slow (global variable)
x = 0
for i in 1:10
x += i # Slow lookup
end
# ✅ Fast (use let or function)
function sum_to_10()
x = 0
for i in 1:10
x += i
end
return x
end
Type Declarations
# Type annotation != conversion
x::Int = 3.14 # InexactError
# Use convert
x::Int = convert(Int, 3.0) # OK
# Type declarations in function args
f(x::Int) = x^2 # Only accepts Int
f(3.14) # MethodError ⚠️
Also see
- Julia Documentation (docs.julialang.org)
- Julia Cheat Sheet (PDF) (juliadocs.github.io)
- Think Julia Book (benlauwens.github.io)
- Julia Performance Tips (docs.julialang.org)
- JuliaHub Package Ecosystem (juliahub.com)
- Julia Discourse Forum (discourse.julialang.org)