(Dynamic) Multiple Dispatch in Julia

Multiple dispatch can be thought of as a generalization of object-oriented (OO) programming.

In a typical OO language like Python, an object type (class) owns certain methods (functions), and are typically called via

object.method(arg1, arg2)

Depending on the type of object, the runtime system will dispatch to different method definitions.

In Julia, the same call would be "spelled" differently:

method(object, arg1, arg2)

Spelled this way, you should notice something odd about OO programming: why is the first argument so special?

Traditional OO programming corresponds to single dispatch: the runtime chooses method based on the type of the first argument only. Julia implements multiple dispatch: the runtime chooses method based on the types of all the arguments.

Example: Binary mathematical operators

A classic example of the need for multiple dispatch is the case of binary math operators. If you compute x * y, the definition of the * function depends upon both the arguments, not just on x.

Julia defines many versions of the * function:


In [1]:
methods(*)


Out[1]:
149 methods for generic function *:
  • *(x::Bool, z::Complex{Bool}) at complex.jl:140
  • *(x::Bool, y::Bool) at bool.jl:50
  • *{T<:Unsigned}(x::Bool, y::T) at bool.jl:63
  • *(x::Bool, z::Complex) at complex.jl:147
  • *(x::Bool, y::Irrational) at irrationals.jl:90
  • *{T<:Number}(x::Bool, y::T) at bool.jl:60
  • *(x::Float32, y::Float32) at float.jl:243
  • *(x::Float64, y::Float64) at float.jl:244
  • *(z::Complex{Bool}, x::Bool) at complex.jl:141
  • *(z::Complex{Bool}, x::Real) at complex.jl:159
  • *(a::Float16, b::Float16) at float16.jl:136
  • *(this::Base.Grisu.Float, other::Base.Grisu.Float) at grisu/float.jl:138
  • *(c::BigInt, x::BigFloat) at mpfr.jl:240
  • *(a::BigInt, b::BigInt, c::BigInt, d::BigInt, e::BigInt) at gmp.jl:298
  • *(a::BigInt, b::BigInt, c::BigInt, d::BigInt) at gmp.jl:291
  • *(a::BigInt, b::BigInt, c::BigInt) at gmp.jl:285
  • *(x::BigInt, y::BigInt) at gmp.jl:255
  • *(x::BigInt, c::Union{UInt16,UInt32,UInt64,UInt8}) at gmp.jl:332
  • *(x::BigInt, c::Union{Int16,Int32,Int64,Int8}) at gmp.jl:338
  • *(a::BigFloat, b::BigFloat, c::BigFloat, d::BigFloat, e::BigFloat) at mpfr.jl:388
  • *(a::BigFloat, b::BigFloat, c::BigFloat, d::BigFloat) at mpfr.jl:381
  • *(a::BigFloat, b::BigFloat, c::BigFloat) at mpfr.jl:375
  • *(x::BigFloat, c::BigInt) at mpfr.jl:236
  • *(x::BigFloat, y::BigFloat) at mpfr.jl:205
  • *(x::BigFloat, c::Union{UInt16,UInt32,UInt64,UInt8}) at mpfr.jl:212
  • *(x::BigFloat, c::Union{Int16,Int32,Int64,Int8}) at mpfr.jl:220
  • *(x::BigFloat, c::Union{Float16,Float32,Float64}) at mpfr.jl:228
  • *(B::BitArray{2}, J::UniformScaling) at linalg/uniformscaling.jl:132
  • *(z::Complex, w::Complex) at complex.jl:127
  • *{T<:Union{Int128,UInt128}}(x::T, y::T) at int.jl:426
  • *{T<:Union{Int128,Int16,Int32,Int64,Int8,UInt128,UInt16,UInt32,UInt64,UInt8}}(x::T, y::T) at int.jl:33
  • *(z::Complex, x::Bool) at complex.jl:148
  • *(x::Real, z::Complex{Bool}) at complex.jl:158
  • *(x::Real, z::Complex) at complex.jl:170
  • *(z::Complex, x::Real) at complex.jl:171
  • *(x::Rational, y::Rational) at rational.jl:206
  • *{N}(a::Integer, index::CartesianIndex{N}) at multidimensional.jl:61
  • *(c::Union{UInt16,UInt32,UInt64,UInt8}, x::BigInt) at gmp.jl:336
  • *(c::Union{Int16,Int32,Int64,Int8}, x::BigInt) at gmp.jl:342
  • *(c::Union{UInt16,UInt32,UInt64,UInt8}, x::BigFloat) at mpfr.jl:216
  • *(c::Union{Int16,Int32,Int64,Int8}, x::BigFloat) at mpfr.jl:224
  • *(c::Union{Float16,Float32,Float64}, x::BigFloat) at mpfr.jl:232
  • *{T<:Number}(x::T, D::Diagonal) at linalg/diagonal.jl:113
  • *(x::Irrational, y::Irrational) at irrationals.jl:88
  • *(y::Real, x::Base.Dates.Period) at dates/periods.jl:90
  • *(x::Number) at operators.jl:116
  • *(y::Number, x::Bool) at bool.jl:65
  • *{T<:Number}(x::T, y::T) at promotion.jl:256
  • *(x::Number, y::Number) at promotion.jl:191
  • *{T<:Union{Complex{Float32},Complex{Float64},Float32,Float64},S}(A::Union{Base.ReshapedArray{T,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,2},SubArray{T,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}, x::Union{Base.ReshapedArray{S,1,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{S,1},SubArray{S,1,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at linalg/matmul.jl:79
  • *(A::SymTridiagonal, B::Number) at linalg/tridiag.jl:98
  • *(A::Tridiagonal, B::Number) at linalg/tridiag.jl:496
  • *(A::UpperTriangular, x::Number) at linalg/triangular.jl:477
  • *(A::Base.LinAlg.UnitUpperTriangular, x::Number) at linalg/triangular.jl:480
  • *(A::LowerTriangular, x::Number) at linalg/triangular.jl:477
  • *(A::Base.LinAlg.UnitLowerTriangular, x::Number) at linalg/triangular.jl:480
  • *(A::Tridiagonal, B::UpperTriangular) at linalg/triangular.jl:1324
  • *(A::Tridiagonal, B::Base.LinAlg.UnitUpperTriangular) at linalg/triangular.jl:1324
  • *(A::Tridiagonal, B::LowerTriangular) at linalg/triangular.jl:1324
  • *(A::Tridiagonal, B::Base.LinAlg.UnitLowerTriangular) at linalg/triangular.jl:1324
  • *(A::LowerTriangular, B::LowerTriangular) at linalg/triangular.jl:1331
  • *(A::Base.LinAlg.UnitLowerTriangular, B::LowerTriangular) at linalg/triangular.jl:1339
  • *(A::UpperTriangular, B::UpperTriangular) at linalg/triangular.jl:1347
  • *(A::Base.LinAlg.UnitUpperTriangular, B::UpperTriangular) at linalg/triangular.jl:1355
  • *(A::Base.LinAlg.AbstractTriangular, B::Base.LinAlg.AbstractTriangular) at linalg/triangular.jl:1472
  • *(A::Base.LinAlg.AbstractTriangular, D::Diagonal) at linalg/diagonal.jl:119
  • *(A::Base.LinAlg.AbstractTriangular, B::Union{Bidiagonal,SymTridiagonal,Tridiagonal}) at linalg/bidiag.jl:415
  • *(A::Base.LinAlg.AbstractTriangular, B::AbstractArray{T<:Any,1}) at linalg/triangular.jl:1496
  • *(A::Base.LinAlg.AbstractTriangular, B::AbstractArray{T<:Any,2}) at linalg/triangular.jl:1496
  • *(A::Union{Base.LinAlg.QRCompactWYQ,Base.LinAlg.QRPackedQ}, b::Union{Base.ReshapedArray{T<:Any,1,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T<:Any,1},SubArray{T<:Any,1,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at linalg/qr.jl:372
  • *(A::Union{Base.LinAlg.QRCompactWYQ,Base.LinAlg.QRPackedQ}, B::Union{Base.ReshapedArray{T<:Any,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T<:Any,2},SubArray{T<:Any,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at linalg/qr.jl:384
  • *(A::Union{Base.ReshapedArray{T<:Any,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T<:Any,2},SubArray{T<:Any,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}, Q::Union{Base.LinAlg.QRCompactWYQ,Base.LinAlg.QRPackedQ}) at linalg/qr.jl:472
  • *{T,S}(Q::Base.LinAlg.HessenbergQ{T,S<:AbstractArray{T<:Any,2}}, X::Union{Base.ReshapedArray{S,1,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},Base.ReshapedArray{S,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{S,1},DenseArray{S,2},SubArray{S,1,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any},SubArray{S,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at linalg/hessenberg.jl:76
  • *{T,S}(X::Union{Base.ReshapedArray{S,1,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},Base.ReshapedArray{S,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{S,1},DenseArray{S,2},SubArray{S,1,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any},SubArray{S,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}, Q::Base.LinAlg.HessenbergQ{T,S<:AbstractArray{T<:Any,2}}) at linalg/hessenberg.jl:80
  • *(A::Base.LinAlg.LQPackedQ, B::Union{Base.ReshapedArray{T<:Any,1,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},Base.ReshapedArray{T<:Any,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T<:Any,1},DenseArray{T<:Any,2},SubArray{T<:Any,1,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any},SubArray{T<:Any,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at linalg/lq.jl:134
  • *{TA,TB}(A::Union{Base.ReshapedArray{TA,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{TA,2},SubArray{TA,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}, B::Base.LinAlg.LQPackedQ{TB,S<:AbstractArray{T<:Any,2}}) at linalg/lq.jl:168
  • *(A::Union{Hermitian{T<:Any,S<:Any},Symmetric{T<:Any,S<:Any}}, B::Union{Hermitian{T<:Any,S<:Any},Symmetric{T<:Any,S<:Any}}) at linalg/symmetric.jl:180
  • *(A::Union{Base.ReshapedArray{T<:Any,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T<:Any,2},SubArray{T<:Any,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}, B::Union{Hermitian{T<:Any,S<:Any},Symmetric{T<:Any,S<:Any}}) at linalg/symmetric.jl:181
  • *{T<:Number}(D::Diagonal, x::T) at linalg/diagonal.jl:114
  • *(Da::Diagonal, Db::Diagonal) at linalg/diagonal.jl:116
  • *(D::Diagonal, B::Base.LinAlg.AbstractTriangular) at linalg/diagonal.jl:120
  • *(D::Diagonal, A::SparseMatrixCSC) at sparse/linalg.jl:114
  • *(D::Diagonal, V::AbstractArray{T<:Any,1}) at linalg/diagonal.jl:117
  • *(D::Diagonal, A::AbstractArray{T<:Any,2}) at linalg/diagonal.jl:124
  • *(A::Bidiagonal, B::Number) at linalg/bidiag.jl:272
  • *(A::Union{Bidiagonal,SymTridiagonal,Tridiagonal}, B::Union{Bidiagonal,SymTridiagonal,Tridiagonal}) at linalg/bidiag.jl:416
  • *{T}(A::Bidiagonal{T}, B::AbstractArray{T,1}) at linalg/bidiag.jl:420
  • *{TX,TvA,TiA}(X::Union{Base.ReshapedArray{TX,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{TX,2},SubArray{TX,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}, A::SparseMatrixCSC{TvA,TiA}) at sparse/linalg.jl:102
  • *{Ta,Tx}(A::Union{Base.ReshapedArray{Ta,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{Ta,2},SubArray{Ta,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}, x::AbstractSparseArray{Tx,Ti<:Any,1}) at sparse/sparsevector.jl:1360
  • *(A::SparseMatrixCSC, x::AbstractSparseArray{Tv<:Any,Ti<:Any,1}) at sparse/sparsevector.jl:1538
  • *{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) at sparse/linalg.jl:125
  • *{TvA,TiA,TvB,TiB}(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) at sparse/linalg.jl:24
  • *(A::SparseMatrixCSC, D::Diagonal) at sparse/linalg.jl:118
  • *(A::Base.SparseArrays.CHOLMOD.Sparse, B::Base.SparseArrays.CHOLMOD.Sparse) at sparse/cholmod.jl:1181
  • *(A::Base.SparseArrays.CHOLMOD.Sparse, B::Base.SparseArrays.CHOLMOD.Dense) at sparse/cholmod.jl:1182
  • *(A::Base.SparseArrays.CHOLMOD.Sparse, B::Union{Array{T<:Any,1},Array{T<:Any,2}}) at sparse/cholmod.jl:1183
  • *{Ti}(A::Symmetric{Float64,SparseMatrixCSC{Float64,Ti}}, B::Union{SparseMatrixCSC{Float64,Ti},SparseVector{Float64,Ti}}) at sparse/cholmod.jl:1584
  • *{Ti}(A::Hermitian{Complex{Float64},SparseMatrixCSC{Complex{Float64},Ti}}, B::Union{SparseMatrixCSC{Complex{Float64},Ti},SparseVector{Complex{Float64},Ti}}) at sparse/cholmod.jl:1585
  • *{Ti}(A::Hermitian{Float64,SparseMatrixCSC{Float64,Ti}}, B::Union{SparseMatrixCSC{Float64,Ti},SparseVector{Float64,Ti}}) at sparse/cholmod.jl:1586
  • *{T<:Number}(x::AbstractArray{T,2}) at abstractarraymath.jl:92
  • *(B::Number, A::SymTridiagonal) at linalg/tridiag.jl:99
  • *(B::Number, A::Tridiagonal) at linalg/tridiag.jl:497
  • *(x::Number, A::UpperTriangular) at linalg/triangular.jl:487
  • *(x::Number, A::Base.LinAlg.UnitUpperTriangular) at linalg/triangular.jl:490
  • *(x::Number, A::LowerTriangular) at linalg/triangular.jl:487
  • *(x::Number, A::Base.LinAlg.UnitLowerTriangular) at linalg/triangular.jl:490
  • *(B::Number, A::Bidiagonal) at linalg/bidiag.jl:273
  • *(A::Number, B::AbstractArray) at abstractarraymath.jl:96
  • *(A::AbstractArray, B::Number) at abstractarraymath.jl:97
  • *(s1::AbstractString, ss::AbstractString...) at strings/basic.jl:84
  • *(index::CartesianIndex, a::Integer) at multidimensional.jl:62
  • *(A::AbstractArray{T<:Any,2}, B::Base.LinAlg.AbstractTriangular) at linalg/triangular.jl:1529
  • *(A::AbstractArray{T<:Any,2}, D::Diagonal) at linalg/diagonal.jl:122
  • *{T,S}(A::AbstractArray{T,2}, x::AbstractArray{S,1}) at linalg/matmul.jl:83
  • *(A::AbstractArray{T<:Any,1}, B::Base.LinAlg.AbstractTriangular) at linalg/triangular.jl:1529
  • *(A::AbstractArray{T<:Any,1}, B::AbstractArray{T<:Any,2}) at linalg/matmul.jl:86
  • *{T,S}(A::AbstractArray{T,2}, B::AbstractArray{S,2}) at linalg/matmul.jl:128
  • *{TA,TB}(A::Base.LinAlg.LQ{TA,S<:AbstractArray{T<:Any,2}}, B::Union{Base.ReshapedArray{TB,1,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},Base.ReshapedArray{TB,2,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{TB,1},DenseArray{TB,2},SubArray{TB,1,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any},SubArray{TB,2,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at linalg/lq.jl:118
  • *{TA,TB}(A::Base.LinAlg.LQ{TA,S<:AbstractArray{T<:Any,2}}, B::Base.LinAlg.QR{TB,S<:AbstractArray{T<:Any,2}}) at linalg/lq.jl:122
  • *{TA,TB}(A::Base.LinAlg.QR{TA,S<:AbstractArray{T<:Any,2}}, B::Base.LinAlg.LQ{TB,S<:AbstractArray{T<:Any,2}}) at linalg/lq.jl:126
  • *(J1::UniformScaling, J2::UniformScaling) at linalg/uniformscaling.jl:131
  • *(J::UniformScaling, B::BitArray{2}) at linalg/uniformscaling.jl:133
  • *(A::AbstractArray{T<:Any,2}, J::UniformScaling) at linalg/uniformscaling.jl:134
  • *(J::UniformScaling, A::Union{AbstractArray{T<:Any,1},AbstractArray{T<:Any,2}}) at linalg/uniformscaling.jl:135
  • *(x::Number, J::UniformScaling) at linalg/uniformscaling.jl:136
  • *(J::UniformScaling, x::Number) at linalg/uniformscaling.jl:137
  • *{T,S}(R::Base.LinAlg.AbstractRotation{T}, A::Union{AbstractArray{S,1},AbstractArray{S,2}}) at linalg/givens.jl:9
  • *{T}(G1::Base.LinAlg.Givens{T}, G2::Base.LinAlg.Givens{T}) at linalg/givens.jl:362
  • *(p::Base.DFT.ScaledPlan, x::AbstractArray) at dft.jl:255
  • *{T,K,N}(p::Base.DFT.FFTW.cFFTWPlan{T,K,false,N<:Any}, x::Union{Base.ReshapedArray{T,N,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,N},SubArray{T,N,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:616
  • *{T,K}(p::Base.DFT.FFTW.cFFTWPlan{T,K,true,N<:Any}, x::Union{Base.ReshapedArray{T,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,N<:Any},SubArray{T,N<:Any,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:623
  • *{N}(p::Base.DFT.FFTW.rFFTWPlan{Float32,-1,false,N<:Any}, x::Union{Base.ReshapedArray{Float32,N,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{Float32,N},SubArray{Float32,N,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:693
  • *{N}(p::Base.DFT.FFTW.rFFTWPlan{Complex{Float32},1,false,N<:Any}, x::Union{Base.ReshapedArray{Complex{Float32},N,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{Complex{Float32},N},SubArray{Complex{Float32},N,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:700
  • *{N}(p::Base.DFT.FFTW.rFFTWPlan{Float64,-1,false,N<:Any}, x::Union{Base.ReshapedArray{Float64,N,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{Float64,N},SubArray{Float64,N,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:693
  • *{N}(p::Base.DFT.FFTW.rFFTWPlan{Complex{Float64},1,false,N<:Any}, x::Union{Base.ReshapedArray{Complex{Float64},N,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{Complex{Float64},N},SubArray{Complex{Float64},N,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:700
  • *{T,K,N}(p::Base.DFT.FFTW.r2rFFTWPlan{T,K,false,N<:Any}, x::Union{Base.ReshapedArray{T,N,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,N},SubArray{T,N,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:848
  • *{T,K}(p::Base.DFT.FFTW.r2rFFTWPlan{T,K,true,N<:Any}, x::Union{Base.ReshapedArray{T,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,N<:Any},SubArray{T,N<:Any,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/FFTW.jl:855
  • *{T}(p::Base.DFT.FFTW.DCTPlan{T,5,false}, x::Union{Base.ReshapedArray{T,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,N<:Any},SubArray{T,N<:Any,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/dct.jl:170
  • *{T}(p::Base.DFT.FFTW.DCTPlan{T,4,false}, x::Union{Base.ReshapedArray{T,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,N<:Any},SubArray{T,N<:Any,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/dct.jl:173
  • *{T,K}(p::Base.DFT.FFTW.DCTPlan{T,K,true}, x::Union{Base.ReshapedArray{T,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray{T,N<:Any},SubArray{T,N<:Any,A<:Union{Base.ReshapedArray{T<:Any,N<:Any,A<:DenseArray,MI<:Tuple{Vararg{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int64},N<:Any}}},DenseArray},I<:Tuple{Vararg{Union{Base.AbstractCartesianIndex,Colon,Int64,Range{Int64}},N<:Any}},L<:Any}}) at fft/dct.jl:176
  • *{T}(p::Base.DFT.Plan{T}, x::AbstractArray) at dft.jl:214
  • *(α::Number, p::Base.DFT.Plan) at dft.jl:257
  • *(p::Base.DFT.Plan, α::Number) at dft.jl:258
  • *(I::UniformScaling, p::Base.DFT.ScaledPlan) at dft.jl:259
  • *(p::Base.DFT.ScaledPlan, I::UniformScaling) at dft.jl:260
  • *(I::UniformScaling, p::Base.DFT.Plan) at dft.jl:261
  • *(p::Base.DFT.Plan, I::UniformScaling) at dft.jl:262
  • *{P<:Base.Dates.Period}(x::P, y::Real) at dates/periods.jl:89
  • *(a, b, c, xs...) at operators.jl:138

We can add new methods to a given function at any time. The methods don't "belong" to a particular type, and aren't part of the type's definition.

For example, string concatenation in Julia is done via *:


In [2]:
"hello" * "world"


Out[2]:
"helloworld"

In [3]:
"hello" + "world"


LoadError: MethodError: no method matching +(::String, ::String)
Closest candidates are:
  +(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:138
while loading In[3], in expression starting on line 1

But we can easily extend + to support a concatenation for strings, if we want:


In [4]:
import Base.+ # we must import a method to add methods (as opposed to replacing it)
+(x::String, y::String) = x * " " * y


Out[4]:
+ (generic function with 164 methods)

In [5]:
"hello" + "world"


Out[5]:
"hello world"

Not the same as C++ overloading: Dynamic vs. static

This may look a lot like function overloading in languages like C++. The difference is that C++'s overloading is static (= dispatch at compile-time), whereas Julia's overloading is dynamic (= dispatch at run-time), like OO polymorphism.

For example, now that we've defined +, we can use strings with any previously defined function that requires a + operation, like sum (summation):


In [6]:
sum(["The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog."])


Out[6]:
"The quick brown fox jumped over the lazy dog."

Type declarations are "function filters"

Type declarations are not required for performance — Julia automatically specializes a function on its argument types during compilation. They act like filters, allowing us to specify which functions are used when.

Without this, in a language like Python, you sometimes have to write manual function filters (see, for example, _parse_args(*args) in Matplotlib's quiver.py).

In Julia, you could define different methods for differing numbers of arguments, arrays vs. scalars, etcetera (all eventually calling a single lower-level function to do the work once the arguments have been transformed).

The work is done by the assertion operator ::, as seen below:


In [7]:
(1+2)::AbstractFloat


LoadError: TypeError: typeassert: expected AbstractFloat, got Int64
while loading In[7], in expression starting on line 1

In [8]:
(1+2)::Int


Out[8]:
3

Julia works with a dynamic tree of types:


In [9]:
Integer <: Number


Out[9]:
true

This allows type assertions attached in-place, both in in-line code and in function declarations. They are useful to structure and describe the logical flow of your program, as well as enabling some performance improvements from the compiler. A type assertion for returned values is also possible; here is an example that gives some of the flavour:


In [10]:
function clip{T<:Real}(x::T, lo::Real, hi::Real)::T
    if x < lo
        return lo
    elseif x > hi
        return hi
    else
        return x
    end
end


Out[10]:
clip (generic function with 1 method)

In [11]:
clip(0.5, 1, 2) # converts lo to T


Out[11]:
1.0

In [12]:
clip(1.5, 1, 2)


Out[12]:
1.5

In [13]:
clip(5//2, 1, 2) # converts hi to T


Out[13]:
2//1