Promoting union types

Since we have

julia> promote_type(Float64, Rational{Int})
Float64

julia> promote_type(Float64, Complex{Rational{Int}})
ComplexF64 (alias for Complex{Float64})

julia> promote_type(Float64, ComplexF64)
ComplexF64 (alias for Complex{Float64})

what I’d expect from promote_type(Float64, Union{Complex{Rational{Int}},Rational{Int}}) is either ComplexF64 (by expanding the union) or Union{ComplexF64,Float64} (by distribution rule). However, Julia gives Number which means it’s trying to find a shared supertype. Why doesn’t Julia implement the two rules that I expect?

1 Like

There simply isn’t a promotion rule defined for this case, so it falls back to typejoin, which gives back Number as a safe fallback.

This is the chain:

julia> promote_type(Float64, Union{Complex{Rational{Int}},Rational{Int}})
Number

julia> promote_rule(Float64, Union{Complex{Rational{Int}},Rational{Int}})
Union{}

julia> promote_rule(Union{Complex{Rational{Int}},Rational{Int}}, Float64)
Union{}

which hits this comment from the source code (see e.g. @edit promote_rule(Int, Float64)):

# If no promote_rule is defined, both directions give Bottom. In that
# case use typejoin on the original types instead.

and thus:

julia> typejoin(Float64, Union{Complex{Rational{Int}},Rational{Int}})
Number

In general though, I wouldn’t expect to get a Union back out of promotion, so IMO this should be ComplexF64 if it were defined.

2 Likes

NOT RECOMMENDED BECAUSE THIS USES INTERNALS but here it is anyway:

julia> Base.promote_union(Union{Float64, Union{Complex{Rational{Int}}, Rational{Int}}})
ComplexF64 (alias for Complex{Float64})

Note that I had to wrap everything in an additional Union to make this work. I’ll recommend you take a peek at the implementation. All it does is recurse on any unions and promote_type when it reaches a pair of non-unions, so you could roll your own version if you wanted to.

3 Likes

A problem is that the a and b fields of a Union object are again not public API. It seems like there should be some supported way of doing this, though. I made an issue/feature request on Julia’s Github:

2 Likes

Interesting find. We document promote_typejoin_union for that, which it seems may be slightly better defined and could probably replace the promote_union there in julia/base/promotion.jl at cfcf8a026276f31eff170fac6ede9d07297d56cf · JuliaLang/julia · GitHub

2 Likes