Methods & Multiple Dispatch
A function is a name; methods are its implementations for different argument types.
15.1 Methods
A function is a name; methods are its implementations for different argument types. Julia picks the most specific method based on the types of all arguments (multiple dispatch).
area(s::Circle) = π * s.r^2
area(s::Point) = 0.0
describe(x) = "something"
describe(x::Number) = "a number"
describe(x::Integer) = "an integer"
describe(x::Integer, y::Integer) = "two integers"
describe(x::String, y) = "a string and something"
describe(1.5) # "a number"
describe(2) # "an integer"
describe(2, 3) # "two integers"
methods(describe) # list all methods
@which describe(2) # which method is called15.2 Multiple dispatch in action
In single-dispatch OOP, a.meet(b) dispatches only on a. Julia dispatches on all arguments — this is how +(::Int, ::Float64), *(::Matrix, ::Vector) etc. are organized, and why packages compose so well.
abstract type Animal end
struct Dog <: Animal end
struct Cat <: Animal end
meet(a::Dog, b::Dog) = "sniffs"
meet(a::Dog, b::Cat) = "chases"
meet(a::Cat, b::Dog) = "hisses"
meet(a::Animal, b::Animal) = "ignores"
meet(Dog(), Cat()) # "chases"
meet(Cat(), Cat()) # "ignores"15.3 Parametric methods
same_type(x::T, y::T) where {T} = true
same_type(x, y) = false
same_type(1, 2), same_type(1, 2.0) # true, false
firstelem(v::AbstractVector{T}) where {T} = isempty(v) ? zero(T) : v[1]15.4 Ambiguities
Check with Test.detect_ambiguities(MyModule).
f(x::Int, y) = 1
f(x, y::Int) = 2
# f(1, 2) → MethodError: ambiguous. Fix by defining f(x::Int, y::Int)15.5 Extending Base functions
Type piracy — extending a Base function for Base types (or another package's types) you don't own — is discouraged.
struct Vec2
x::Float64
y::Float64
end
Base.:+(a::Vec2, b::Vec2) = Vec2(a.x + b.x, a.y + b.y)
Base.:*(k::Real, v::Vec2) = Vec2(k * v.x, k * v.y)
Base.zero(::Type{Vec2}) = Vec2(0, 0)
Base.length(::Vec2) = 2
sum([Vec2(1, 2), Vec2(3, 4)]) # works because + and zero are defined15.6 Callable objects (functors)
struct Polynomial
coeffs::Vector{Float64}
end
(p::Polynomial)(x) = evalpoly(x, p.coeffs)
p = Polynomial([1, 2, 3]); p(2.0) # 1 + 2x + 3x² = 17.015.7 Function barriers & dispatch on values
process(::Val{:fast}, x) = "fast path"
process(::Val{:safe}, x) = "safe path"
process(mode::Symbol, x) = process(Val(mode), x)