Promote and infinite recursion

question

#1

When reading the code of IntervalSets.jl I saw a constructor defined like this:

checked_conversion{T}(::Type{T}, a, b) = _checked_conversion(T, convert(T, a), convert(T, b))
_checked_conversion{T}(::Type{T}, a::T, b::T) = a, b
_checked_conversion{T}(::Type{T}, a, b) = throw(ArgumentError("$a and $b are not both of type $T"))

immutable ClosedInterval{T} <: AbstractInterval{T}
    left::T
    right::T

    ClosedInterval(l::T, r::T) = new(l, r)
end

ClosedInterval{T}(left::T, right::T) = ClosedInterval{T}(left, right)
(::Type{ClosedInterval{T}}){T}(left, right) =
    ClosedInterval{T}(checked_conversion(T, left, right)...)

function ClosedInterval(left, right)
    # Defining this as ClosedInterval(promote(left, right)...) has one problem:
    # if left and right do not promote to a common type, it triggers a StackOverflow.
    T = promote_type(typeof(left), typeof(right))
    ClosedInterval{T}(checked_conversion(T, left, right)...)
end

My question: is this the current best practice? Reading the manual on parametric constructors I was not aware of the issue.


#2

It seems reasonable to me. It looks like this is similar to the handling at https://github.com/JuliaLang/julia/blob/bfc72b6fe913236ccb2bdd1ef254bceccb0cc31a/base/promotion.jl#L167-L179. I see there’s still a TODO there though about trying to handle this StackOverflow better. Perhaps the ideas from that code could be used to help improve it?