Why does a = Vector{<:Real}(undef, 2)
fail, giving the following error?
MethodError: no method matching Array{#s1,1} where #s1<:Real(::UndefInitializer, ::Int64)
(Julia version 1.0)
Why does a = Vector{<:Real}(undef, 2)
fail, giving the following error?
MethodError: no method matching Array{#s1,1} where #s1<:Real(::UndefInitializer, ::Int64)
(Julia version 1.0)
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.
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
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
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).
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
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 havePoint{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