v06 I want to write a signature that expect 2 to 3 arguments. The first one is either an Integer or Vector of Integer. The second one is either a Vector of Integer or Matrix of Integer. The third one is either a Vector of Integer or not specified.
I first tried it like this
function foo(
a::Union{Integer, Vector{Integer}},
b::Union{Vector{Integer}, Matrix{Integer}},
c::Union{Void, Vector{Integer}} = nothing)
When I call this like this foo(3, [0o7, 0o5])
I get an error telling me that it is unable to match.
ERROR: LoadError: MethodError: no method matching foo(::Int64, ::Array{UInt8,1})
Closest candidates are:
foo(::Union{Array{Integer,1}, Integer}, !Matched::Union{Array{Integer,1}, Array{Integer,2}}) at ...
foo(::Union{Array{Integer,1}, Integer}, !Matched::Union{Array{Integer,1}, Array{Integer,2}}, !Matched::Union{Array{Integer,1}, Void}) at ...
Now I understand why julia is unable to match this Array{UInt8} <: Array{Integer} == false
, but this just seems to be not smart of julia.
Then I tried this
foo(a::Union{Z1, Vector{Z1}},
b::Union{Vector{Z2}, Matrix{Z2}},
c::Union{Void, Vector{Z3}} = nothing
) where {Z1 <: Integer, Z2 <: Integer, Z3 <: Integer}
Now julia does not even tell me what does not match!
ERROR: LoadError: MethodError: no method matching foo(::Int64, ::Array{UInt8,1}, ::Void)
Closest candidates are:
foo(::Union{Array{Z1<:Integer,1}, Z1<:Integer}, ::Union{Array{Z2<:Integer,1}, Array{Z2<:Integer,2}}, ::Union{Array{Z3<:Integer,1}, Void}) where {Z1<:Integer, Z2<:Integer, Z3<:Integer} at ...
foo(::Union{Array{Z1<:Integer,1}, Z1<:Integer}, ::Union{Array{Z2<:Integer,1}, Array{Z2<:Integer,2}}) where {Z1<:Integer, Z2<:Integer} at ...
foo(a, b, c=nothing)
, in favour offoo(a, b, c)
andfoo(a, b)
. Also, consider whether there is a connection between the types, for example, isa
aVector
only whenb
is aMatrix
? – DNFc
isVoid
, if I didn't supply anyc
at all! Suggestion: Split your function into separate methods with correct signatures. Then make a fallback method (or several) that catches the rest:f(a, b, c) = ...
without types, and let that one figure out what's wrong with the inputs and issue errors. – DNFfoo(a::Integer, b::Vector{<:Integer}) = ... end
foo(a::Vector{<:Integer}, b::Matrix{<:Integer}, c::Vector{<:Integer}) = ... end
foo(a::Integer, b...) = error("If a is an Integer, b must be a Vector of Integers.") end
foo(a::Vector{<:Integer}, b...) = error("If a is an Vector of Integers, b must be a Matrix of Integers and c must be a Vector of Integers...") end
(ends added for readability, it's not actually correct to use them.) I think this will actually make it easier to write good error messages. – DNF