Why Union{} <: Tuple?

question

#1
  1. Why is Union{} <: Tuple?

  2. When Base.Broadcast._broadcast_eltype returns Union{}, what does that mean? That it could not infer an eltype?

On v"0.6.0".


#2

Union{} was originally None, renamed in Julia 0.4 (https://github.com/JuliaLang/julia/issues/8423). In Julia’s type hierarchy, this is a “bottom” type: Union{} <: T is true for every type T, so it is at the “bottom” of the type hierarchy. (In fact, Base.Bottom is an alias for Union{}.)

My understanding is that having a bottom type made various things easier, e.g. the promotion machinery: https://github.com/JeffBezanson/phdthesis/blob/876be73a5aab9b034fac3eb9ea9d8f96713f786f/chap5.tex … it gives the type system the algebraic structure of a lattice, which makes it easier to reason about (https://github.com/JeffBezanson/phdthesis/blob/876be73a5aab9b034fac3eb9ea9d8f96713f786f/chap3.tex).


#3

Thanks! I missed the renaming.

The issue came up when defining

"""
    fixed_tuple_fields(T)

When `T` is a `Tuple{...}` with a nonzero, fixed number of elements (ie no
`Vararg`), return those; in all other cases `()`.
"""
fixed_tuple_fields(T::Type{<:Tuple}) =
    (T.parameters[end] <: Vararg) ? () : tuple(T.parameters...)

How can I define this method so that it is defined for all “proper” Tuples, but not Union{}?


#4

Regarding the second question: it seems like Union{} is returned as an inferred type when the function does not return on any path. Eg

julia> foo(x) = error("all paths lead to an error")
foo (generic function with 1 method)

julia> Base._return_type(foo, Int)
Union{}

Is this correct?


#5

Correct. Consider the following:

(a ? foo() : bar())

what’s the inferred type of that whole expression? Well it’s the union of whatever foo returns (let’s take Union{}) and whatever bar returns (say Int). I.e. it’s Union{Union{}, Int} and by standard type system rules:

julia> Union{Union{}, Int}
Int64