# I am surprised that promotion does not occur here

Consider the following:

``````julia> [[1,2,3]//3,[1,2,3]*Int128(1)]
2-element Array{Array{T,1} where T,1}:
Rational{Int64}[1//3, 2//3, 1//1]
Int128[1, 2, 3]
``````

Julia cannot compute the type of the combined array, but Julia is able to compute

``````julia> promote_type(Rational{Int64},Int128)
Rational{Int128}
``````

but curiously this does not carry over to arrays:

``````julia> promote_type(Vector{Rational{Int64}},Vector{Int128})
Array{T,1} where T
``````

Though this works in a slightly different case:

``````julia> promote_type(Vector{Int64},Vector{Int128})
Array{Int128,1}
``````

I am surprised and went through the source to find what happens. The stuff happens in `typejoin`,
which is very complicated and does not seem to use promotion of `eltype`. Can someone explain that to me, and why the simpler case is handled but not the more complicated one?

1 Like

Seems like it should happen, given that

``````julia> [[1,2,3]//3,[1,2,3]*0.5]
2-element Vector{Vector{Float64}}:
[0.3333333333333333, 0.6666666666666666, 1.0]
[0.5, 1.0, 1.5]
``````

Actually my question is motivated by a problem I have in my code, with different types. I am expecting that when I have defined (or Julia has defined) `T=promote_type(T1,T2)` (and a `promote_rule` also) then elements in a mixed vector of `T1` and `T2` are promoted to `T` (this happens) and also that mixed `Vector{T1}` and `Vector{T2}` in a `Vector` are promoted to `Vector{T}` (this is very inconsistent, depending on `T1` and `T2`).

yeah no that should not be expected:

``````julia> promote_type(BigInt, Float32)
BigFloat

julia> promote_rule(Vector{BigInt}, Vector{Float32})
Vector{T} where T (alias for Array{T, 1} where T)
``````

Basically I think 1) itâ€™s not clear thereâ€™s a definitive rule regarding how far should Julia go to promote different nested types such that it appears to be natural and â€ścompletedâ€ť to our eyes. 2) even if there is a mathematically sound rule, it may be too much cost to *always do it.

1 Like

Ok but then can anyone document what happens? Which examples work and which do not?

1 Like

I believe this is an implementation detail (depending on heuristics). (think of trying to document when will a function be inlined)

Overall, there is never a type-promotion covariance(?) promised by Julia in the docs anywhere to begin with, so thereâ€™s no need to document a non-feature.

1 Like

I had in my mind that Julia should have something like

`promote_rule(Array{T},Array{T1})=Array{promote_type(T,T1)}`

but perhaps it does not make senseâ€¦

(sorry my previous example post had a bug that I used `promote_rule` in both places)

I would have imagined the same, maybe others would agree we should specialize on promote_rule for `Array`s.

That mental model seem to work on `Real` subtypes except for when you mix `BigInt` and `Float**` together.

I think itâ€™s the right thing to not promote container types.

``````julia> [[1,2,3]//3,[1,2,3]*0.5]
2-element Vector{Vector{Float64}}:
[0.3333333333333333, 0.6666666666666666, 1.0]
[0.5, 1.0, 1.5]
``````

is fine because itâ€™s the result of a literal evaluation, but letâ€™s put it slightly differently:

``````julia> vec_rat = [1,2,3]//3;

julia> vec_float = [1,2,3]*0.5;

julia> vecs = [vec_rat, vec_float]
2-element Array{Array{Float64,1},1}:
[0.3333333333333333, 0.6666666666666666, 1.0]
[0.5, 1.0, 1.5]
``````

Do you spot a problem?

Now `vecs[2]` is bound to `vec_float` but `vecs[1]` and `vec_rat` are completely decoupled. WTH?

I donâ€™t spot a problem since `promote_type(Rational{Int},Float64)==Float64`. I wish this would happen consistently. Do you spot a problem?

The problem is, when one writes `c = [a, b]`, is it fine if `c[1] !== a` or `c[2] !== b` when `a` and `b` are mutable?

2 Likes

Well, we saw some examples where the promotion happened. I would think there is no problem
when `a` and `b` are arrays; or otherwise one should prohibit the examples which worked above.
For me the problem is the inconsistency.

Inconsistency is indeed a problem.
Iâ€™d just ignore the existence of type promotion for arrays of arrays and write my own function for the specific case I need, though.

2 Likes

One could argue that the problem you highlight is a question of `!==` being too coarse a measure of equality for the case in hand.

According to the manual:

39.18 Be careful with type equality
You generally want to use isa and <: for testing types, not ==. Checking types for exact equality typically only makes sense when comparing to a known concrete type (e.g. T == Float64), or if you really, really know what youâ€™re doing.