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

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)

1 Like

`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.

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

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`

2 Likes

`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`.

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

1 Like

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.

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).

1 Like

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
``````
1 Like

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

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]``````

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.
1 Like