Call original method when redefining a method. (Compact float printing in IJulia)

I want to print floats (and derived types such as Unitful.Quantity{Float64, …}) compactly in IJulia / the REPL.

E.g. 0.1*3 should be echoed as 0.3 and not 0.30000000000000004.
Likewise, 0.1*3mV should be 0.3 mV and not 0.30000000000000004 mV.

The canonical way to print compactly seems to be show(IOContext(stdout, :compact=>true), 0.1*3).

To achieve this automatically for all echoes (i.e. without having to type the above show incantation in every cell), I’d like to define something like:

Base.show(io::IO, x::Float64) = 
    show(IOContext(io, :compact=>true), x)

This yields a StackOverflowError because we redefined the method in terms of itself.
The desired behaviour would be for the show in our function’s body to refer to the original float-showing method in Base.

My question is, how can we do this?
More generally: how do you call the original method when redefining a method?

(Research note: in a previous thread on the same problem this was resolved by calling Base.Grisu._show. This cannot be done anymore as “Grisu” has been replaced by “Ryu”, and Ryu only defines Base.show itself, not any inner function like _show.)

Maybe you can take a look at

https://github.com/ronisbr/PrettyNumbers.jl

To call the old method, you want invoke, or now @invoke:

julia> @which show(stdout, 3.14)
show(io::IO, x::T) where T<:Union{Float16, Float32, Float64} in Base.Ryu at ryu/Ryu.jl:111

julia> Base.show(io::IO, x::Float64) = 
             Base.@invoke show(IOContext(io, :compact=>true)::IO, x::Union{Float16, Float32, Float64})

julia> pi .^ (0,1,2)
(1.0, 3.14159, 9.8696)
1 Like

Thank you, that works nicely.
TIL about invoke.

This does not seem to work if the overriding method has the exact same signature though.

For example, I want to override show(io::IO, x::Quantity) from Unitful and use the original function definition in my new method. I currently just copy-paste the original function body (and import needed symbols), but that’s not super nice.

For that, use invoke, not @invoke.