Why is the dispatch behavior different for the following codes? The only difference is that the type parameter T of the abstract type is restricted (<:Real) in the first snippet and unrestricted in the second snippet.
abstract type Abstract{T<:Real} end
struct Concrete{T} <: Abstract{T}
Concrete(t) = new{typeof(t)}()
end
[Concrete(1), Concrete(1.0)] isa Vector{<:Abstract} # false
[Concrete(1), Concrete(1.0)] isa Vector{<:Abstract{<:T}} where {T} # true
abstract type Abstract2{T} end
struct Concrete2{T} <: Abstract2{T}
Concrete2(t) = new{typeof(t)}()
end
[Concrete2(1), Concrete2(1.0)] isa Vector{<:Abstract2} # true
[Concrete2(1), Concrete2(1.0)] isa Vector{<:Abstract2{<:T}} where {T} # true
Thanks to both of you. I was calling it dispatch because in my original code came up when I tried to dispatch on Vector{<:Abstract} and it threw a MethodError.
I was wrongly assuming, that concrete types inherit the abstract type parameter constraint, which is why I put it there in the first place. So that I cannot construct concert subtypes violating that constraint.
Now it makes sense! Or at least I understand the rules, even though I still find them quite unintuitive. I’ll just omit the type restriction in my abstract type then.