`Tuple` of `Union` or `Union` of `Tuple`?

I want to annotate a type-unstable variable with a type-parameter constraint to improve the chance of union splitting during compilation. In general, should I do Tuple of Union or Union of Tuple?

For example, which of the following struct is better, assuming T1 and T2 have different underlying data structures?

struct TofU{T1, T2}
    a::NTuple{2, Union{T1, T2}}
end

struct UofT{T1, T2}
    a::Union{Tuple{T1, T2}, Tuple{T2, T1}, NTuple{2, T1}, NTuple{2, T2}}
end

Note that for any given T1 and T2 (T1 != T2), though NTuple{2, Union{T1, T2}} and Union{Tuple{T1, T2}, Tuple{T2, T1}, NTuple{2, T1}, NTuple{2, T2}} represent two “equal” types, they are not identical (egal):

julia> T1 = Int
Int64

julia> T2 = Float64
Float64

julia> t1 = NTuple{2, Union{T1, T2}}
Tuple{Union{Float64, Int64}, Union{Float64, Int64}}

julia> t2 = Union{Tuple{T1, T2}, Tuple{T2, T1}, NTuple{2, T1}, NTuple{2, T2}}
Union{Tuple{Float64, Float64}, Tuple{Float64, Int64}, Tuple{Int64, Float64}, Tuple{Int64, Int64}}

julia> t1 == t2
true

julia> t1 === t2
false

Hence, I assume there is some non-negligible overhead difference in compilation or dispatch process.

Only unions of tuples participate in the union-splitting optimizations, so those tend to perform better.

1 Like