I asked this question some time ago on slack, posting now the answers here to avoid the slackhole of oblivion.
Thanks to @jakobnissen, @Sukera, and @tecosaur for the information.
Question
When should I define methods for print
and when should I define show(MIME"text/plain")
? I understand that bare two-argument show/repr
are supposed to be “kinda parseable Julia-specific on best effort basis” and that print/string
is supposed to be human readable (as print
’s docstring says). But the show
docstring also says to define a three-argument show(MIME"text/plain")
method for human consumption (in addition to a two-argument show
that is “kinda parseable”). My question would not really matter if print
defaulted to show(MIME"text/plain")
, but print
actually defaults to the two-argument show
.
So… should we consider changing the default print
to be show(MIME"text/plain")
? If that default is not changed, should I be defining custom methods for print
or for show(MIME"text/plain")
when I want “human readable” representation?
Main Answer
These are three distinct methods, with slightly different meanings. They can be demonstrated using Char
:
julia> print(stdout, 'P')
P
julia> show(stdout, 'P')
'P'
julia> show(stdout, MIME"text/plain"(), 'P')
'P': ASCII/Unicode U+0050 (category Lu: Letter, uppercase)
I.e.
print
is the textual representation: What does this object look like when printed to the screen? Here,'P'
doesn’t have the'
symbols, it’s just printed as a plainP
- Two-arg show is: “The simple representation in the REPL”, i.e. the parsable one. Essentially it’s the “Julia notation” for the object
- Three-arg show is the fancy, bells and whistles representation for the repl which may span multiple lines and give extra info. That’s essentially a kind of “dump this object into the REPL”
Most types don’t need to define all three. For example:
String
s need to distinguish between print and show (since only the latter includes the"
marks), but not between two- and three-arg show, since there is no fancy representation of a stringVector
s don’t really have a textual printed representation - when printed, it just gives the “Julia notation”, i.e. the same as two-arg show. Because vectors are not really meant to be printed as strings. However, vectors do have a fancy three-arg show method (the one that begins with with “3-element Vector{Int}:”, then writes an element per line)Int
s need neither a fancy representation. nor a textual representation, so all three methods just end up in the same place
One more wrinkle is that, at least when I looked the last time, while the printing system is quite nice and flexible, it’s underdocumented, and in some cases even buggy with unstated assumptions that are violated elsewhere (very Julian). This has been an outstanding issue for many years but no-one has taken the time to clean it up
TLDR
if all you want is human readable representation, define the three arg show
Comments on use in the ecosystem
One issue with the 2 vs. 3 arg show and the way it’s done across the ecosystem is that it’s hard to have:
- A pretty multi-line version (3-arg show)
- A pretty compact version (3-arg show with compact IO)
- A non-pretty repr-evaluable version (2-arg show)
- The plain printing version (print)
The issue is with (2) the “pretty compact version”, which is often desirable when a value is to be displayed as part of another value (e.g. a Dict
/ Vector
element, or some nested structure).It’s possible to handle this all correctly, but that requires consistent use of 3-arg show within other 3-arg show implementations, and consistent checking of io.compact
. Unfortunately, neither are done consistently (edited)
My 2c: with hindsight it would have been best if different signatures were used for “short pretty” and “long pretty” methods