What interface to implement for `round(x, digits=n)` to work?

There is a section in the documentation that explains what methods to implement to support rounding on a new type:

Apparently, one needs to implement round(x::ObjType, r::RoundingMode). The section even includes an example for an interval type:

julia> struct Interval{T}
           min::T
           max::T
       end

julia> Base.round(x::Interval, r::RoundingMode) = Interval(round(x.min, r), round(x.max, r))

julia> x = Interval(1.7, 2.2)
Interval{Float64}(1.7, 2.2)

julia> round(x)
Interval{Float64}(2.0, 2.0)

However, this method is not enough for the keyword arguments digits and sigdigits to work:

julia> round(x, digits=0)
ERROR: MethodError: no method matching round(::Interval{Float64}, ::RoundingMode{:Nearest}; digits::Int64)

julia> round(x, sigdigits=1)
ERROR: MethodError: no method matching round(::Interval{Float64}, ::RoundingMode{:Nearest}; sigdigits::Int64)

What methods should I implement so that these calls work? I can make it work by implementing

round(x::Interval, r::RoundingMode; 
      digits::Union{Integer,Nothing}=nothing, 
      sigdigits::Union{Integer,Nothing}=nothing)

but I am not sure if that’s intended.

In general I would expect you should also explicitly provide e.g. digits, since it’s not always obvious what it would mean to round up to n digits. (Say you want to round a Date. Then ‘digits’ might mean you want to round up to a day, week, month, etc. But there will not be any default mechanism to fall back on. (Edit: round is actually already canonically implemented for Dates, where you should just provide Day, Week, Month,… The keyword digits is not supported. :slight_smile: )

But in this case you can just pass through all keyword arguments to round(::T).

julia> Base.round(x::Interval, r::RoundingMode=RoundNearest; kwargs...) = Interval(round(x.min, r, kwargs...), round(x.max, r, kwargs...))

julia> I = Interval(1.32, 5.88)
Interval{Float64}(1.32, 5.88)

julia> round(I)
Interval{Float64}(1.0, 6.0)

julia> round(I, digits=1)
Interval{Float64}(1.3, 5.9)
1 Like

Thank you. Yes, in the case of Interval, you can do that, but that’s only possible because the fields are floats for which we already have the methods with the keyword arguments implemented.

Maybe I should have been more specific in the first post. I am working on implementing rounding for the Decimal type (Normal by barucden · Pull Request #88 · JuliaMath/Decimals.jl · GitHub), which is a subtype of AbstractFloat.

The keyword arguments digits and sigdigits make sense for rounding a Decimal, and I have an implementation. However, I already had to add some extra methods to resolve ambiguities, and the whole thing starts to feel “awkward”, which makes me think that I am not connecting to the whole round-machinery as I should.