Passing arrays with unspecified type

As a general rule, it is important to label fields of a struct or the elements of a container you are constructing with their types, but you do not need to label the types of your function inputs for performance. In fact, it says so right here in the manual: Performance Tips · The Julia Language

In many languages with optional type declarations, adding declarations is the principal way to make code run faster. This is not the case in Julia. In Julia, the compiler generally knows the types of all function arguments, local variables, and expressions.

What that means is that any of the following function definitions will give exactly the same performance:

function f1(a)  # matches any `a`; equivalent to `a::Any`
  ...
end

function f2(a::AbstractArray)  # matches an array with any number of dimensions
  ...
end

function f3(a::AbstractVector)  # matches an array with exactly one dimension
  ...
end

function f4(a::AbstractVector{<: Number})  # matches an array with exactly one dimension
                                           # whose elements are all some kind of `Number`
  ...
end

function f5(a::Vector{Float64})  # matches only exactly a Vector of Float64
  ...
end

Try it! Define each of those functions and install BenchmarkTools.jl via:

]add BenchmarkTools

and then do:

using BenchmarkTools
@btime f1($a)
@btime f2($a)
@btime f3($a)
@btime f4($a)
@btime f5($a)

So why would you choose f4 instead of f1 ? Adding types to your function arguments is a matter of API design. If you define an f4(a::AbstractVector{<:Number}), then you can also define f4(a::SomeOtherType) and the compiler will automatically pick the appropriate method for whatever input is passed in. Or you might choose to specify your argument types as a signal to users of your code so that they know what you’re expecting them to provide.

11 Likes