JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.83k stars 5.49k forks source link

Undesirable automatic conversion from`Vector{Vector{T}}` to `Vector{T}` #56527

Open thchr opened 1 week ago

thchr commented 1 week ago

I accidentally stumbled on the following:

julia> v = Union{Vector{Int}, Nothing}[Vector{Int}[] for _ in 1:3]

This returns a Vector{Union{Vector{Int}, Nothing}} but, really, I think it should error. The issue is that the elements in [Vector{Int}[] for _ in 1:3] are not Vector{Int} but Vector{Vector{Int}}, so we have scenario of the kind Union{A, B}[c::C for c in ...] with C not a subtype of A or B.

The reason this works is that each of the Vector{Int}[] elements are passed on to the conversion machinery. In particular, as pointed out by @thofma on Slack, this is probably passed to one of these methods:

julia> convert(Vector{Int}, Vector{Int}[]) # Int64[]
julia> Vector{Int}(Vector{Int}[]) # Int64[]

It's hard to see where this would be desirable though. Additionally, the conversion only works if the to-be-converted-array is empty. That is, the following fails:

julia> convert(Vector{Int}, Vector{Int}[[1,2,3],[4,5]])
julia> Vector{Int}(Vector{Int}[[1,2,3],[4,5]])

It seems strange and error-prone to have conversion methods that only work for empty input.

raminammour commented 1 week ago

The culprit seems to be this line: https://github.com/JuliaLang/julia/blob/ad243681bddad93d4b700d1417e0d45d00a31fc1/base/array.jl#L302

jakobnissen commented 1 week ago

In my opinion, this is API, and thus can't be changed. It's bad API, but nonetheless.

mbauman commented 1 week ago

This isn't unique to vectors of vectors. You can convert any empty array to any other empty array, regardless of the eltypes:

julia> convert(Vector{Nothing}, Some[])
Nothing[]

julia> convert(Vector{Nothing}, Any[])
Nothing[]

julia> convert(Vector{Nothing}, Vector{Matrix{Dict{Any,Any}}}[])
Nothing[]
thchr commented 1 week ago

This isn't unique to vectors of vectors. You can convert any empty array to any other empty array, regardless of the eltypes:

Is that a nice thing to be able to do?

mbauman commented 1 week ago

Well, it tracks with the ability to convert array eltypes in general. It works if you can convert the elements. So in the empty case — where there are no elements around to throw a wrench — it works.

julia> convert(Vector{Int}, Any[0x1, 2.0, 3//1])
3-element Vector{Int64}:
 1
 2
 3

julia> convert(Vector{Int}, Any[])
Int64[]

Or perhaps more typically, you might have:

julia> convert(Vector{Int}, Union{Int, Missing}[1])
1-element Vector{Int64}:
 1

julia> convert(Vector{Int}, Union{Int, Missing}[])
Int64[]

Those are definitely useful behaviors, even though Any or Union{Int, Missing} vectors can hold things that definitely cannot convert to Int. Now, yes, they are slightly different in that they are able to hold things that can convert. But it's definitely not trivial to figure that out in general.