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