I defined the following:
import Base: promote_rule
struct RationalNumber{T<:Integer} <: Real
num::T
den::T
end
#RationalNumber{T}(x::S) where {T<:Integer, S<:Integer} = RationalNumber(x, 1)
RationalNumber(n::T, d::T) where {T<:Integer} = RationalNumber{T}(n,d)
RationalNumber(n::Integer, d::Integer) = RationalNumber(promote(n,d)...)
RationalNumber(n::Integer) = RationalNumber(n, one(n))
RationalNumber{T}(n::Integer) where {T<:Integer} = convert(T, n) |> RationalNumber
promote_rule(::Type{RationalNumber{T}}, ::Type{S}) where {T,S<:Integer} = RationalNumber{promote_type(T, S)}
promote_rule(::Type{RationalNumber{T}}, ::Type{RationalNumber{S}}) where {T,S<:Integer} = RationalNumber{promote_type(T, S)}
function Base.show(io::IO, r::RationalNumber)
print(io, "$(r.num)//$(r.den)")
end
I am working on getting comparison to behave properly. Currently, it’s fine when I compare a RationalNumber{T} to another with the same T:
julia> RationalNumber{Int8}(2,3) == RationalNumber{Int8}(2,3)
true
But I get an error when comparing a RationalNumber{T} and RationalNumber{U} where T != U:
julia> RationalNumber(2,3) == RationalNumber{Int8}(2,3)
ERROR: MethodError: no method matching RationalNumber{Int64}(::RationalNumber{Int8})
Closest candidates are:
(::Type{T})(::T) where T<:Number
@ Core boot.jl:792
(::Type{RationalNumber{T}} where T<:Integer)(::Any, ::Any)
@ Main Untitled-1:848
(::Type{T})(::AbstractChar) where T<:Union{AbstractChar, Number}
@ Base char.jl:50
...
Stacktrace:
[1] convert(#unused#::Type{RationalNumber{Int64}}, x::RationalNumber{Int8})
@ Base ./number.jl:7
[2] _promote
@ ./promotion.jl:358 [inlined]
[3] promote
@ ./promotion.jl:381 [inlined]
[4] ==(x::RationalNumber{Int64}, y::RationalNumber{Int8})
@ Base ./promotion.jl:449
[5] top-level scope
@ REPL[4]:1
I expected my second promote_rule method to handle this, but I guess I’m misunderstanding something. Can someone help me properly fix this? I’m inclined to write another constructor which handles the MethodError, but I’m not sure if this is the best way to do it.