Since this particular case is not explicitly answered (implied in the other comments/answers)
So let me try
I think the starting point should be to accept the fact:
Real == (T where T <: Real)
The same holds true when we replace Real
with any other type. so Any == (T where T <:Any)
, etc
The above relation means that type Real
is the union of Real
and its all subtypes (abstract or concrete)
that is, Real == Union{Real, Rational, Integer, String, etc}
We can confirm this fact with simple type hierarchy:
let
abstract type A end
abstract type B<:A end
struct C<:B end
@assert A == Union{A, B, C}
@assert B == Union{B, C}
end
I feel this relation is weird because it means that something is equal to a set that contains it.
But once the rule is accepted, the rest can be explained based upon it without difficulty.
First, Vector{Any} vs Vector{<:Any}
:
Vector{Any}
is a short-hand notation for Vector{T where T<:Any}
(note this is same to Vector{T where T}
wihout <:Any
suffix). Therefore Vector{Any}
means a Vector
whose element is of type Any
. (note Any == (T where T<:Any)
). So [1, "a"]
and [1, 2]
are all valid instance of Vector{Any}
On the other hand, Vector{<:Any}
is a short-hand notation of Vector{T} where T<: Any
((note this is same to Vector{T} where T
). Also, in REPL, Vector{<:Any}==( Vector{T} where T<: Any)
is confirmed. Therefore Vector{<:Any}
is equal to a collection of types {Vector{Any}, Vector{Number}, Vector{String}, ...} == Union{Vector{Any}, Vector{Number}, Vector{String}, ...}
. That is, Vector{Any}
is an element in the set Vector{<:Any}
and it means Vector{Any}
is a proper subtype of Vector{<:Any}
. Also in REPL, we can confirm that Vector{Any}<:Vector{<:Any} && Vector{Any}!=Vector{<:Any}
indeed.
Vector{Vector{Any}} vs Vector{Vector{<:Any}}
:
Now, Vector{Any}
is a proper subtype of Vector{Vector{<:Any}}
Due to type invariance property of Array in Julia, when T1
is a proper subtype of T2
Vector{T1}
can not be a subtype of Vector{T2}
Therefore Vector{Vector{Any}}
can not be a subtype of Vector{Vector{<:Any}}
This is confirmed in REPL by checking Vector{Vector{Any}} <: Vector{Vector{<:Any}}
false.
This reasoning explains why isa(Vector{Vector{Any}}(), Vector{Vector{T} where T})
is false.
However without relying on the formality, I think we can understand the relation with just common sense. That is, I think a type is defined by what it is capable of.
So, the Vector
in Vector{Vector{Any}}
is capable of accepting an element only if the element is of type Vector{Any}
. that is the Vector is “restrictive”
but the Vector
in Vector{Vector{<:Any}}
is capable of accepting an element as long as the type of the element is any one of Vector{Any}, Vector{Int}, Vector{String}
, etc.
In other words, this Vector is “generous” (relative to the previous one)
If Vector{Vector{<:Any}}
were a supertype of Vector{Vector{Any}}
, it means Vector{Vector{Any}}
is-a Vector{Vector{<:Any}}
which then comes to imply a restrictive type is-a generous type, which sounds contradictory.
Another source of confusion to new comers, I think, is the fact that [1, 2] isa Vector{Any}
is false
although [1, 2]
is a valid instance of Vector{Any}
. In fact [1, 2]
an instance of Vector{Any}
and at the same time it is an instance of Vector{Int}
but recall that Vector{Any} != Vector{Int}
nor Vector{Int} <: Vector{Any}
so of what type should [1,2]
be? it is up to the compiler unless you specify as you wish it to be. The compiler always choose the least common ancestor of two element 1 and 2 which is Int64
so typeof([1,2])==Vector{Int64}
which is not subtype of Vector{Any}
by type invariance. Therefore, [1, 2] isa Vector{Any}
is false
although [1, 2]
is a valid instance of Vector{Any}
I hope my thought hasn’t brought further confusion to the discussion and also understand my not smooth English! If there is any error in my thought, please fix it!