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 like1:3include both ends. - The dot in
.+is not decoration: it marks broadcast, which applies an operation elementwise. Without it,v + 10is 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| Type | Literal | Notes |
|---|---|---|
| Int64 | 42 | Machine integer; overflow wraps silently |
| BigInt | big(42) | Arbitrary precision, much slower |
| Float64 | 1.0, 1e-3 | The default in numerical code |
| Rational | 1 // 3 | Exact fractions, no rounding |
| String | "text" | UTF-8 and immutable |
| Symbol | :name | An 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 |
| Dict | Dict("a" => 1) | Hash table; key order is not insertion order |
| Nothing / Missing | nothing, 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.Related
Multiple dispatch Python: getting started
Last refreshed 2026-09-18.