My function f(x::Vector)
works on a vector of numbers (e.g. x=[0.1, 0.2]
).
However, I’d like to create another method for vector of vectors (e.g. x=[[0.1, 0.2], [0.3, 0.4]]
), which uses the vector-of-numbers version.
However, it seems that x=[0.1, 0.2]
and x=[[0.1, 0.2], [0.3, 0.4]]
are of the same type: the vector-of-vectors is caught and processed by the first version.
How can I specify vector-of-vectors and vector-of-numbers as types to dispatch on? Thank you!
I’d recommend using broadcasting in this case: that’s just f.([[0.1, 0.2], [0.3, 0.4]])
. Broadcasting works element-wise across the container you pass it, without needing to define an additional method.
A vector of vectors is indeed just a vector. The difference is in its element type:
f(x::Vector{<:Number}) = "vector of numbers"
f(x::Vector{<:Vector}) = "vector of vectors"
julia> f([1,2,3])
"vector of numbers"
julia> f([[1,2],[3,4]])
"vector of vectors"
But note that this isn’t the same as saying what they contain — it’s just a property of the vector itself. In fact, you can have vectors that contain just numbers and won’t work with the above, because they can contain Any
thing:
julia> f(Any[1,2,3])
ERROR: MethodError: no method matching f(::Array{Any,1})
Closest candidates are:
f(::Array{#s1,1} where #s1<:Real) at REPL[10]:1
f(::Array{#s1,1} where #s1<:(Array{T,1} where T)) at REPL[10]:2
Stacktrace:
[1] top-level scope at none:0
4 Likes
Awesome, thanks for that comprehensive reply!
I would just add a change to the type notation as my preferred one,
if you wanted to allow a more flexible approach which I don’t particularly recommend,
f(obj::AbstractVector) = all(elem isa Number for elem ∈ obj) ?
f(convert(Vector{reduce(promote_type, typeof(elem) for elem ∈ obj)}, obj)) :
throw(ArgumentError("elements should all be numbers"))
f(::AbstractVector{<:Number}) = ...
I would just keep the second one.