Type inference for vcat


#1

Hi all,

I’m just trying to understand the rules for type inference when using vcat. Consider the following operations on v0.7:

vcat(Int[], 1)
vcat(String[], "a")
vcat(UnitRange{Int}[], 1:1)
vcat(Vector{Int}[], [1])

return respectively a Vector{Int}, Vector{String}, Vector{Any}, and Vector{Any}. Observing the first two operations, I would have thought the rule was for any type T, inputting values with types (Vector{T}, T) to vcat would return Vector{T}, but type inference seems to break down for the last two operations. Is this a bug, or indicative of some subtler behaviour that I’m not seeing?

EDIT: even weirder, note that:

julia> vcat([1:1], 1:1)
2-element Array{Any,1}:
  1:1
 1   

How did I get an Int as the second element of the output!?! That definitely feels like a bug.

Cheers,

Colin


#2

I think you meant to write:


julia> vcat(Int[], [1])
1-element Array{Int64,1}:
1

or

julia> vcat(Vector{Int}[]..., [1]) 
1-element Array{Int64,1}:  
1

Hm, what would you have expected? vcat makes a vector consisting of all the elements of the first input and then all the elements of the second input. All elements of 1:1 are just 1.


#3

No, I definitely meant vcat(Vector{Int}[], [1]), since it was the input type pattern (Vector{T}, T) I was targeting in my test cases (in this case, T is Vector{Int}).

The behaviour I was expecting was for a call to vcat with input types (Vector{T}, T) to always result in Vector{T} output, eg I was expecting vcat([1:1], 1:1) to return [1:1, 1:1]. But what you said here

explains the source of my misunderstanding. My heuristic output type rule derived from the first two test-cases breaks down when T is a subtype of AbstractArray. And I can see the logic now for doing it the way it is done. It allows us to do really nice things like vcat([1,2,3], 4:6). In my head, I was imagining vcat([1,2,3], 4:6) would need to be written vcat([1,2,3], collect(4:6)).

Thanks for clearing up my misunderstanding. The only thing I’m still a bit hesitant about is why vcat(Int[], 1) is allowed at all? A scalar doesn’t really have any elements, so shouldn’t this op be an error? Or am I asking something that has been hashed out in a github issue long ago and doesn’t need to be revived? :slight_smile:


#4

That was indeed discussed at length on github, but the conclusion was that numbers are iterable:

julia> for i in 1
       @show i
       end
i = 1  

Thus they should be vcatable.


#5

Understood. Thanks again for taking the time to explain.


#6

You’re welcome. I think there is a “solved”-thingy you can click.


#7

Note that inference isn’t involved here, these are actually promotion rules.


#8

Yes, this whole thread really boils down to me thinking it was an inference issue and not a promotion issue :slight_smile: