Syntax and the type system

Functions, arrays and interpolation, plus the concrete and abstract types that decide how fast the code runs.

Familiar syntax, one-based arrays

square(x) = x^2                       # the one-line function form
hypot2(x, y) = sqrt(x^2 + y^2)

function mean_and_sd(v)
    m = sum(v) / length(v)
    s = sqrt(sum((v .- m).^2) / (length(v) - 1))
    return m, s                        # returns a tuple
end

m, s = mean_and_sd([1.0, 2.0, 3.0, 4.0])

name = "Julia"
println("$name sums 1:10 to $(sum(1:10))")

v = [1, 2, 3]
w = v .+ 10            # the dot broadcasts the addition over the vector
v[1]                   # 1, because indexing starts at 1
v[end]                 # 3, and 'end' is syntax, not a function
  • Indexing is 1-based. v[0] is a BoundsError, and ranges like 1:3 include both ends.
  • The dot in .+ is not decoration: it marks broadcast, which applies an operation elementwise. Without it, v + 10 is a dimension mismatch.
  • Functions are values and can be anonymous: f = x -> x^2, map(x -> x^2, v).
  • String interpolation is $(expression) inside a double-quoted string; single quotes are for characters.
  • Matrices are column-major, so [1 2; 3 4] is two rows and looping down a column is the cache-friendly direction.

Types are optional to write and impossible to ignore

typeof(1)          # Int64 on a 64-bit build
typeof(1.0)        # Float64
typeof(1 // 2)     # Rational{Int64}
typeof("a")        # String

abstract type Shape end

struct Circle <: Shape
    r::Float64
end
area(c::Circle) = pi * c.r^2

circle = Circle(2.0)
area(circle)             # 12.566...

Circle isa DataType       # true: Circle is the type, not a value
circle isa Shape          # true: subtype relation tested on a value
Float64 <: Real           # true: use <: between two types
TypeLiteralNotes
Int6442Machine integer; overflow wraps silently
BigIntbig(42)Arbitrary precision, much slower
Float641.0, 1e-3The default in numerical code
Rational1 // 3Exact fractions, no rounding
String"text"UTF-8 and immutable
Symbol:nameAn interned identifier, not text
Vector / Matrix[1, 2], [1 2; 3 4]One-based, column-major
Tuple(1, "a")Heterogeneous, immutable, stack-allocated
NamedTuple(a = 1, b = 2)Field names, and it keeps its order
DictDict("a" => 1)Hash table; key order is not insertion order
Nothing / Missingnothing, missing"No value" versus "unknown value"
💡
There is no class inheritance for data. You compose structs and dispatch on their types; abstract types exist only to group concrete types so methods can target a family. Declaring a struct field with an abstract type — x::Number rather than x::Float64 — forces the compiler to box it and is the usual reason a struct-based program is slower than a bare loop.

FAQ

Do I have to annotate types for speed?
Almost never inside ordinary functions, because the compiler infers them. You annotate to constrain the API (only accept a Float64) or to fix a type instability the compiler is reporting. Concrete struct fields are the one place annotations genuinely matter.
Why did my integer arithmetic overflow?
Julia's Int64 wraps around silently, exactly like C. Use big(), Int128, or Base.checked_mul when the values can exceed the machine range.

Multiple dispatch Python: getting started

Last refreshed 2026-09-18.