RealInfinity is declared abstract and exported, which invites downstream subtypes:
abstract type RealInfinity <: Real end
struct PositiveInfinity <: RealInfinity end
struct NegativeInfinity <: RealInfinity end
However signbit is defined only on the two concrete types, with no ::RealInfinity fallback, and sign, angle and every T(x::RealInfinity) conversion are built on it:
signbit(::PositiveInfinity) = false # src/Infinities.jl:52-53
signbit(::NegativeInfinity) = true
sign(y::RealInfinity) = 1-2signbit(y) # :71
angle(x::RealInfinity) = π*signbit(x) # :72
_convert(::Type{T}, x::RealInfinity) where {T<:Real} = sign(x)*convert(T, Inf) # :64
So a third subtype does not fail cleanly:
julia> struct ThirdInfinity <: Infinities.RealInfinity end
julia> signbit(ThirdInfinity())
ERROR: StackOverflowError:
julia> Float64(ThirdInfinity())
ERROR: StackOverflowError:
It falls through to Base.signbit(x::Real) = x < 0 (number.jl:137) and the comparison then recurses.
Two ways to make the assumption explicit:
-
Non-breaking — add a signbit(::RealInfinity) fallback that throws a clear error, so an unsupported subtype produces a message instead of a stack overflow.
-
Breaking — put the closure in the type system:
struct PositiveInfinity <: Real end
struct NegativeInfinity <: Real end
const RealInfinity = Union{PositiveInfinity, NegativeInfinity}
The second option is what was probably intended, at least if the intent is that the extended real line has exactly two points at infinity — with directional infinities living in ComplexInfinity{T} — then option 2 states that in the type system rather than in convention.
RealInfinityis declared abstract and exported, which invites downstream subtypes:However
signbitis defined only on the two concrete types, with no::RealInfinityfallback, andsign,angleand everyT(x::RealInfinity)conversion are built on it:So a third subtype does not fail cleanly:
It falls through to
Base.signbit(x::Real) = x < 0(number.jl:137) and the comparison then recurses.Two ways to make the assumption explicit:
Non-breaking — add a
signbit(::RealInfinity)fallback that throws a clear error, so an unsupported subtype produces a message instead of a stack overflow.Breaking — put the closure in the type system:
The second option is what was probably intended, at least if the intent is that the extended real line has exactly two points at infinity — with directional infinities living in
ComplexInfinity{T}— then option 2 states that in the type system rather than in convention.