If parametric types are invariant, why is Vector{Int} a subtype of AbstractVector{Int}?

If parametric types are invariant, why is `Vector{Int}` a subtype of `AbstractVector{Int}`?

``````julia> Vector{Int} <: AbstractVector{Int}
true
``````

A somewhat more complete and self-contained example:

``````julia> abstract type Animal{T} end

julia> struct Cat{T} <: Animal{T} end

julia> Int <: Real
true

julia> Cat{Int} <: Animal{Real}
false

julia> Int <: Int
true

julia> Cat{Int} <: Animal{Int}
true
``````

Since parametric types are supposed to be invariant, it seems like there should be no subtype relationship between `Cat{Int}` and `Animal{Int}`

1 Like

Your example is consistent with the first code block right? (this is not invariance or not, just abstract types mechanics)
And also consistent examples:

``````julia> Vector{Int} <: AbstractVector{Real}
false

julia> AbstractVector{Int} <: AbstractVector{Real}
false
``````
2 Likes

Oh, right, I already forgot that type invariance means that
`S <: T` does not imply `A{S} <: A{T}`.

Whereas my example is `B{T} <: A{T}`

It still feels slightly inconsistent though…

2 Likes

One way to think about it is that `Vector{Real}` is a concrete type while `AbstractVector{Int}` isn’t. As such `Vector{Real}` can’t be the supertype of anything, and `AbstractVector{Int}` can.

3 Likes

That’s a good point. Since `AbstractVector{Int}` is an abstract type, there must be something which is a subtype of it. Or rather, it must be possible for something to be a subtype of it.

2 Likes