Improving doc for display/print/show/repr/

Continuing on what was started in (wrong forum?) https://github.com/JuliaLang/julia/issues/14052#issuecomment-927458219

Questions

  • Why would we use repr() over string()?
    • Clearly, the call stack is different (sprint vs print_to_string) — but I can’t figure out why.
  • Why does print() drop ::MIME in the print layer — instead of delegating that choice to the show layer?

A little background information

Peering into the display/print/show system

Using the following to probe into specific call stacks:

Base.show(io::IO, o::SomeObj) = throw("Dump Call Stack: No MIME")
#Base.show(io::IO, ::MIME"text/plain", o::SomeObj) = throw("Dump Call Stack: MIME")

Observations: Julia print/display system

show() call stacks

show(::SomeObj) -> show(::IO, ::SomeObj)
show(::MIME, ::SomeObj) -> NO IMPLEMENTATION! (that's fine; ::IO is simply required)
show(::IO, ::MIME, ::SomeObj) -> show(::IO, ::SomeObj) #Default behaviour

NOTE:

  • Might want to implement show(::IO, ::MIME"text/plain", ::SomeObj) for pretty printing

print() call stacks

print(::SomeObj) -> print(::IO, ::SomeObj) -> show(::IO, ::SomeObj)
print(::MIME, ::SomeObj) -> print(stdout::IO, ::MIME, ::SomeObj) -> print(::IO, ::SomeObj) -> show(::IO, ::SomeObj)
print(::IO, s::STRING) -> write(::IO, s) #BYPASS SHOW COMPLETELY FOR STRINGS

NOTE:

  • Doesn’t use show(::IO, ::MIME"text/plain", ::SomeObj) for pretty printing (even if ::MIME is specified).

WARNING: The following statements do not work in an orthogonal way:

  • print(MIME("text/plain"), "SomeString")
  • print(stdout, MIME("text/plain"), "SomeString")

They print the ::MIME, then the ::String. They do not use ::MIME to specialize formatting of print().

repr() call stacks

repr(::SomeObj; context) -> sprint(::Function{show}, ::SomeObj; context) -> show(::IO, :SomeObj)
repr(::MIME, ::SomeObj; context) -> show(::IO, ::MIME, ::SomeObj) -> show(::IO, ::SomeObj)

NOTE:

  • Uses show(::IO, ::MIME"text/plain", ::SomeObj) for pretty printing if ::MIME is provided.

string() call stacks

string(::SomeObj) -> print_to_string(::SomeObj) -> print(::IO, ::SomeObj) -> show(::IO, ::SomeObj)
string(::MIME, ::SomeObj) -> print_to_string(::MIME, ::Vararg) -> print(::IO, ::SomeObj) -> show(::IO, ::SomeObj)

NOTE:

  • Doesn’t use show(::IO, ::MIME"text/plain", ::SomeObj) for pretty printing (even if ::MIME is specified).

display() call stacks

With a TextDisplay <: Base.AbstractDisplay @ top of display stack (see pushdisplay()):

display(::SomeObj) -> display(::TextDisplay, ::SomeObj) -> display(::TextDisplay, ::MIME"text/plain", ::SomeObj)

Which would typically then call an appropriate MIME-aware show() function, for example:

show(::IO, ::MIME"text/plain", ::SomeObj) -> show(::IO, ::SomeObj) #Default fallback

NOTE:

  • Thus, a user-defined type should explicitly define said MIME-aware show() function for “pretty-printing”:
    • show(::IO, ::MIME"text/plain", ::SomeObj)
  • Fancier displays (ex: Jupyter notebooks) might support richer ::MIME formats by calling specialized methods, for example:
    • show(::IO, ::MIME"text/html", ::SomeObj)
    • show(::IO, ::MIME"image/png", ::SomeObj)
    • (Specialized methods are typically implemented by the package defining ::SomeObj)

User-defined AbstractDisplays

With a user-defined CustomDisplay <: Base.AbstractDisplay @ top of display stack:

display(::SomeObj) -> display(::CustomDisplay, ::SomeObj) #NO DEFAULT IMPLEMENTATION

Thus, to work with display() system, user must implement custom:

  • display(::CustomDisplay, ::Any)
  • and/or display(::CustomDisplay, ::SomeObj)

WARNING:

  • display(::SomeObj) never to be implemented directly for risk of breaking display() system.
4 Likes

I agree some work is still needed in this area.

The difference between repr("a") == "\"a\"" and string("a") == "a" seems right to me.

However, as I wrote in Distinguish string functions for data values vs programmer information · Issue #40779 · JuliaLang/julia · GitHub I do think there remains some issues here — though it may be necessary to wait till 2.0 to fix them. In particular, the idea of “printing the value itself” seems inapplicable to most types and usages of print(x) and string(x) are likely to be bugs for those types – the exceptions being String, Int, and some others.

Sorry. Got sidetracked when I first outlined this issue - haven’t have much time to look deeper into it. Decided to include graphical view of call stack before I forget I made it (for a second time):

8 Likes

Quick summary, since this thread never seems to have concluded.

string calls print (as documented here) which (by default) calls the 2-argument show (documented here, though it doesn’t say 2-arg specifically).

display (by default, in the REPL) calls the 3-argument show with text/plain which (by default) calls 2-argument show. Documented in the manual’s section on custom pretty-printing.

1-arg repr calls 2-arg show (documented here, though it doesn’t mention 2-arg specifically), and 2-arg repr (documented here) calls 3-arg show.

(This can all be overloaded, of course — one big exception to the above rules is for strings, in which case show and hence repr add quotation marks and backslash escaping of special characters, whereas print just outputs the raw string. This is mentioned in the print docs.)

The big omission from the docs is that the print and 1-arg repr functions just say that they call show, but should specifically say that they call the 2-argument show. I think this is because those functions pre-date the 3-arg show. PR to fix this omission: document that print(x) and repr(x) call 2-arg show by stevengj · Pull Request #53927 · JuliaLang/julia · GitHub

8 Likes