You don´t need to repeat all types, just up to the one where dispatch is needed. Thus, the idea is to put first the types that are needed for dispatch. For example:
julia> struct A{T1,T2}
x::T1
y::T2
end
julia> f(a::A{T1}) where {T1<:Int} = "Int"
f (generic function with 2 methods)
julia> f(a::A{T1}) where {T1<:Float64} = "Float64"
f (generic function with 2 methods)
julia> f(A(1,2))
"Int"
julia> f(A(1.0, 2))
"Float64"
I don’t think we have anything like this with _, but if there are parameters you want to “ignore” you can write them as <:Any. Like F{<:Any, <:TargetSupertype, <:Any, <:AnotherType}. Note that an inline <:X is a shorthand for something like _X with a where {_X <: X} at the end (although _X is something I made up and what the compiler uses will be sure to be unique), so those substitutions are equivalent to F{A, B, C, D} where {A,B<:TargetSupertype,C,D<:AnotherType}. Note also that where A<:Any is equivalent to where A, which is why I didn’t expand those fully.
Ah, of course. This syntax I knew but somehow didn’t think to use. Thanks for the suggestion. Both suggestions together make everything a lot easier to write and maintain in my code. Thanks!
Can you be a bit more specific? For example you might have ran into the warning from Types · The Julia Language ? If so see the two code blocks afterwards for the fix.
I’ve got the impression that the first one is considered more “specialized” by the compiler but don’t remember reading anything explaining the difference in the Julia docs.
julia> (AbstractArray{<:Any, B} where {B}) == (AbstractArray{A, B} where {A, B})
true
Also, when I define both in a fresh REPL session (using AbstractArray as an example type) I only get one method at the end. Seems like they are exactly the same:
julia> f(::AbstractArray{A,B}) where {A,B} = B
f (generic function with 1 method)
julia> f(::AbstractArray{<:Any,B}) where {B} = B
f (generic function with 1 method)
julia> methods(f)
# 1 method for generic function "f" from Main:
[1] f(::AbstractArray{<:Any, B}) where B
@ REPL[4]:1
But funnily enough, if I define the first method again in the same session, it changes the printout of methods to match the way it was defined. Perhaps because === is not true for both types written above.
julia> f(::AbstractArray{A,B}) where {A,B} = B
f (generic function with 1 method)
julia> methods(f)
# 1 method for generic function "f" from Main:
[1] f(::AbstractArray{A, B}) where {A, B}
@ REPL[6]:1
Unless I am missing something super subtle here, the only difference is that you cannot use the type parameter A directly in the function body