Promote constructor causing stack overflow

julia> struct parametrict{T}

julia> parametrict(a::Real, b::Real) = parametrict(promote(a, b)...)

julia> parametrict(0.5, 0.5)
ERROR: StackOverflowError:
 [1] parametrict(::Float64, ::Float64) at ./REPL[2]:1 (repeats 80000 times)

The Julia docs seem to suggest doing exactly this, perhaps they should be updated? And what’s the recommended method for accomplishing this right now (i.e. making all sets of real input Just Work regardless of type)? I’m also using version 1.1.1 if that makes any difference.

Your definition of parametric is not the same with the one in the doc:

julia> struct Point{T<:Real}
           Point{T}(x,y) where {T<:Real} = new(x,y)  # this is the main difference

And another definition is missing

julia> Point(x::T, y::T) where {T<:Real} = Point{T}(x,y);

This was the key to fixing the problem, rather than the inner constructor. After playing with it a bit I realized that the where {T<:Real} is the key element; remove that and you get the stack overflow again. My guess is that the default constructor Julia supplies to such a type looks like this:

Point(x::T, y::T) where {T} = Point{T}(x,y)

and if you define the promote method on Reals with only this default constructor, the promote method always gets selected as the most specific method for Real input and continues to call itself, leading to the stack overflow.

EDIT: Upon reading the docs more closely, another valid solution is to just specify struct Point{T<:Real} instead of just plain struct Point{T} (or struct parametrict{T}). That annotation alone changes the default constructor to the form specified explicitly in your answer!

1 Like