Why does a = Vector{<:Real}(undef, 2) fail?

question

#1

Why does a = Vector{<:Real}(undef, 2) fail, giving the following error?
MethodError: no method matching Array{#s1,1} where #s1&lt;:Real(::UndefInitializer, ::Int64)

(Julia version 1.0)


#2

Vector{<:Real} (short of Vector{T} where T<:Real) is not a concrete type and in this case it’s unclear what exactly you want to construct so there isn’t a method defined for this to guess what you want.


#3

But, c = Vector{Real}(undef, 2) works, while Real isn’t a concrete type.


#4

That’s exactly why I spelled out the type for you. Real isn’t a concrete type but Vector{Real} is. Vector{T} where T<:Real isn’t a concrete type because it’s a class (UnionAll) of types constraint by the where


#5

Vector{Real} is a concrete type, a vector holding any Real.

What would be the element type of Vector{<:Real} ? You haven’t specified T.


#6

Thank you for the comment. I wasn’t aware a = Vector{T} where T<:Real was of UnionAll. When I checked d = Vector{T} where T<:Real; typeof(d) , it’s UnionAll, indeed :slight_smile:


#7

Actually, I was creating a vector of vectors vv = Vector{Vector{<:Real}}(undef, 2), which worked. So, I assumed vv[1] = Vector{<:Real}(undef, 2) would work. Well, it seems I was wrong.

In practice, I’ll do vv[1] = Vector{Real}(undef, 2) and will have no problem.

Now, it’s still unclear to me why vv above works… when I checked the type of vv above, it’s DataType.


#8

And that’s exactly why I always hated the <: notation… Vector{Vector{<:Real}} is Vector{Vector{T} where T<:Real}, i.e. a Vector of the abstract type Vector{T} where T<:Real. It is not Vector{Vector{T}} where T<:Real which would be an abstract type (UnionAll). <:T isn’t a value (there’s no value X where Vector{X} is Vector{<:Real}) rather a syntax that moves out of the enclosing{}. However, it only move one level of {} making it really confusing for beginners (and expers when not paying attention).


#9

Yes I can see why this seems confusing.

One way to look at it is you can create a concrete Vector with an abstract element type as long as that element type is well specified.
However you can’t create a Vector with “unspecified” element type.

Perhaps related, compare:

Vector{Vector{Real}}             # concrete
Vector{Vector{T} where T<:Real}  # concrete
Vector{Vector{T}} where T<:Real  # abstract, T not specified

#10

Thank you for the comments. Now I understand the subtle syntax issue much better.


#11

As mentioned above, use of <: such as Vector{Matrix{<:Real}} is a bit confusing…

a = [[1 2 3;4 5 6],[3 2 1;6 5 4]]

function temp(a::Vector{Matrix{<:Real}})
    a
end
temp(a)
MethodError: no method matching temp(::Array{Array{Int64,2},1})
Closest candidates are:
  temp(::Array{Array{#s1,2} where #s1<:Real,1}) at In[1]:4
It's the same as
function temp1(a::Vector{Matrix{T} where T<:Real})
    a
end
temp(a)
MethodError: no method matching temp(::Array{Array{Int64,2},1})
Closest candidates are:
  temp(::Array{Array{#s1,2} where #s1<:Real,1}) at In[1]:4

However, this works:

function temp2(a::Vector{<:Matrix{<:Real}})
    a
end
temp2(a)
2-element Array{Array{Int64,2},1}:
 [1 2 3; 4 5 6]
 [3 2 1; 6 5 4]

I sort of understand why, but will appreciate a good explanation.

As suggested in one of the comments above in this thread, maybe better avoid such use of <: if I don’t understand it very well? The following function works well and easier to understand.

function temp3(a::Vector{Matrix{T}} where T<:Real)
    a
end
temp3(a)
2-element Array{Array{Int64,2},1}:
 [1 2 3; 4 5 6]
 [3 2 1; 6 5 4]

#12

Because parametric types in Julia are invariant. From documentation:

This last point is very important: even though Float64 <: Real we DO NOT have Point{Float64} <: Point{Real}.

So translating this to your case:

  • Vector{Matrix{Int}} <: Vector{Matrix{<:Real}} is false.
  • Vector{Matrix{Int}} <: Vector{<:Matrix{Real}} is false.

But if you want covariance then

  • Vector{Matrix{Int}} <: Vector{<:Matrix{Int}} is true
  • Vector{Matrix{Int}} <: Vector{<:Matrix{<:Real}} is true
  • Vector{Matrix{Int}} <: Vector{Matrix{T}} where T<:Real is true
  • etc.