Why [1, 2, 3] is not a Vector{Number}?

It is all about whether the container (or container of containers) holds abstract types (versatile but slow) or concrete types (restrictive but fast).

v1 = [1, 2]      # 2-element Vector{Int64}
v2 = [1.1, 2.2]  # 2-element Vector{Float64}
vv1 = Vector{<:Number}[]  # 0-element Vector{Vector{<:Number}}
push!(vv1, v1)            # 1-element Vector{Vector{<:Number}}
push!(vv1, v2)            # 2-element Vector{Vector{<:Number}}
vv2 = Vector{Int64}[]  # 0-element Vector{Vector{Int64}}
push!(vv2, v1)         # 1-element Vector{Vector{Int64}}
push!(vv2, v2)  # Error: vv2 container can only hold Vector{Int64} elements
vv1 isa Vector{Vector{<:Number}}   # true
vv2 isa Vector{Vector{<:Number}}   # false
vv1 isa Vector{<:Vector{<:Number}} # true
vv2 isa Vector{<:Vector{<:Number}} # true

I asked a related question here which may also be useful to you.

2 Likes

First, let’s construct a simple Vector{Vector{Float64}}

# Simple Vector{Vector{Float64}}
julia> a = [[3.0]]
1-element Vector{Vector{Float64}}:
 [3.0]

julia> typeof(a)
Vector{Vector{Float64}} (alias for Array{Array{Float64, 1}, 1})

Is a a subtype of Vector?

julia> typeof(a) <: Vector
true

Is a a subtype of Vector of Vectors with unspecified element type?

julia> typeof(a) <: Vector{Vector}
false

Is a a subtype of Vector with element types that are a subtype of Vector?

julia> typeof(a) <: Vector{<: Vector}
true

Is a a subtype of Vector with element types that are a subtype of Vector with element type Number?

julia> typeof(a) <: Vector{<: Vector{Number}}
false

Is a a subtype of Vector with element types that are a subtype of Vector with element type Float64?

julia> typeof(a) <: Vector{<: Vector{Float64}}
true

Is a a subtype of Vector with element types that are a subtype of Vector with an element type that is a
subtype of Number?

julia> typeof(a) <: Vector{<: Vector{<: Number}}
true

Let’s go through the false answers and create the appropriate types for them to be true.

julia> vv = Vector[ [3.0] ]
1-element Vector{Vector}:
 [3.0]

julia> typeof(vv) <: Vector{Vector}
true

julia> vvn = Vector{Number}[ Number[3.0] ]
1-element Vector{Vector{Number}}:
 [3.0]

julia> typeof(vvn) <: Vector{<: Vector{Number}}
true

Why does this matter?

In the first case with a :: Vector{Vector{Float64}} we can figure out that the first element of the first vector will be of type Float64.

image

In the case case with vv :: Vector{Vector} we do not know the element type at all. It could be anything. We’re as clueless as Python in this case. @code_warntype will warn us about this situation by highlighting the uncertainty in type information in red.

image

If we specify Number as the element type we know a little information, but not specifically that the element type is Float64:

image

Why does it matter if we know the element type? In subsequent code, it would be best if we know the element type so that we can compile the actual machine instructions to use as well as some hints about how the numbers are arranged in memory. If we do not know the type, we cannot make performance enhancing instructions about memory and we cannot figure what exact machine instructions to use.

I will leave it to Professor Steven G. Johnson to explain further.

6 Likes