# \`print\` vs two-argument \`show\`/\`repr\` vs three-argument \`show\`/\`repr\` with \`MIME"text/plain"\`

**URL:** https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790
**Category:** General Usage
**Tags:** pretty-printing
**Created:** [August 3, 2024, 5:51pm UTC](https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790 "2024-08-03T17:51:17Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![Krastanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/krastanov/32/6817_2.png) [@Krastanov](https://discourse.julialang.org/u/Krastanov)
#### Post date: [August 3, 2024, 5:51pm UTC](https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790/1 "2024-08-03T17:51:17Z")

</div>

> 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-repl
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 plain `P`
- 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 string
- `Vector` 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

# Previous discussion

> <https://github.com/JuliaLang/julia/issues/40030>
>
> The \`show\` docstring claims that 3-argument \`show(io, mime::MIME"text/plain", xs…)\` for containers is implemented by calling \`show(IOContext(io, :compact=\>true), mime, x)\` on the container elements:
> \`\`\`
> julia\> VERSION
> v"1.7.0-DEV.706"
> 
> help?\> show
> ...
> show(\[io::IO = stdout\], x)
> ...
> To customize human-readable text output for objects of type T, define
> show(io::IO, ::MIME"text/plain", ::T) instead. Checking the :compact IOContext
> property of io in such methods is recommended, since some containers show their
> elements by calling this method with :compact =\> true.
> ...
> show(io::IO, mime, x)
> ...
> Container types generally implement 3-argument show by calling show(io,
> MIME"text/plain"(), x) for elements x, with :compact =\> true set in an IOContext
> passed as the first argument.
> 
> help?\> IOContext
> ...
> IOContext(io::IO, KV::Pair...)
> ...
> • :compact: Boolean specifying that values should be printed more compactly,
> e.g. that numbers should be printed with fewer digits. This is set when
> printing array elements. :compact output should not contain line breaks.
> \`\`\`
> 
> However, containers in the standard library don't follow this practice.
> 1. \`Vector\` calls \`show()\` twice: first \`show(io, "text/plain", x)\`, then, if the output contains line breaks, \`show(io, x)\`; \`:compact\` is not actually set.
> 2. \`Array{T,N}\` for \`N\>1\` does the same, but sets \`:compact =\> true\`.
> 3. \`Set\` calls \`show(io, x)\` and truncates the output to fit the display width.
> 4. \`Dict\` calls \`show(io, x)\` with \`:compact =\> true\`, and also truncates the output.
> 5. Although \`:compact\` output should not contain line breaks, this requirement is not respected by the containers themselves.
> 6. \`Pair\` and \`Ref\` don't implement 3-argument \`show()\`.
> 
> Third-party libraries, such as \`DataFrames\` and \`PrettyTables\`, appear to use 2-argument \`show\` with \`:compact =\> true\` and truncate the output, pretty similar to \`Dict\`.
> 
> It seems either the \`show\` docstring or how \`show\` is implemented for standard containers should be fixed. Or, perhaps, both?
> 
> Overall, it's unclear how to properly implement \`show\` for custom types, especially containers or types with complex output layout. Perhaps, it deserves its own section in the \*Interfaces\* page of the Manual?
> 
> Aside from that, a couple of random notes:
> 
> For 2-argument \`show\`, \`:compact =\> true\` implies constrained horizontal space. However the role of \`:compact =\> true\` in 3-argument \`show\` is unclear. Is it supposed to restrict the output to a single line? Perhaps, that should be expressed with a separate context parameter?
> 
> The implementation of \`show\` for \`Array\` types can cause exponential behavior:
> \`\`\`
> julia\> nested(w, h) = h \> 0 ? Any\[nested(w, h-1) for j = 1:w\] : nothing
> julia\> @time show(devnull, nested(6, 6))
> 0.006758 seconds (121.31 k allocations: 4.271 MiB)
> julia\> @time show(devnull, "text/plain", nested(6, 6))
> 6.292005 seconds (5.45 M allocations: 439.713 MiB, 0.36% gc time)
> \`\`\`
> 
> \`Vector\` and \`Set\` have identical output layouts, but print their elements very differently.
> 
> The fact that \`Dict\` truncates the output works fine for flat dictionaries, but not very convenient for JSON data.

> [@Improving doc for display/print/show/repr/](https://discourse.julialang.org/t/improving-doc-for-display-print-show-repr/69124/3):
>
> 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):

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [August 3, 2024, 6:38pm UTC](https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790/2 "2024-08-03T18:38:07Z")

</div>

I recently added a summary to the docs that should help (though I think all of this info was there before, albeit scattered): [add summary of x::T output functions by stevengj · Pull Request #54547 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/54547)

You should mostly only define `print` methods for string/char-like types, for which there is a canonical “plain text” representation of the object that is distinct from how you input it into Julia. Dates are another example IIRC.

---

<div class="post-metadata">

### Author: ![MatthijsCox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matthijscox/32/42831_2.png) [@MatthijsCox](https://discourse.julialang.org/u/MatthijsCox)
#### Post date: [August 8, 2024, 8:35am UTC](https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790/3 "2024-08-08T08:35:54Z")

</div>

I once wrote a short blog post with an example of how I typically define my own [custom show function](https://scientificcoder.com/user-defined-show-method-in-julia) which also goes into the compact mode for printing objects inside an array, maybe it’s helpful for this discussion.

I would actually be curious to see an overview of all possible IO options used in Julia base show functionality. So far I found `compact` and `limit`.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [August 8, 2024, 12:32pm UTC](https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790/4 "2024-08-08T12:32:29Z")

</div>

> [@MatthijsCox](#):
>
> I once wrote a short blog post with an example of how I typically define my own [custom show function](https://scientificcoder.com/user-defined-show-method-in-julia) which also goes into the compact mode for printing objects inside an array, maybe it’s helpful for this discussion.

I don’t think you should be using `:compact=>false` with 2-argument `show` as a synonym for 3-argument/multi-line `show`.

With or without `:compact`, the 2-argument `show` should generally be a `repr` format that corresponds to Julia input. `:compact` is more about things like the number of digits to print. Your implementation, in contrast, mean that things like `println(io, "x = ", x, ", y = ", y)` will give a multi-line output for `x::MyType` if the `:compact=>false` flag is set on `io`.

Moreover, `:compact=>false` should be the _default_ for both 2-argument and 3-argument `show`.

> [@MatthijsCox](#):
>
> I would actually be curious to see an overview of all possible IO options used in Julia base show functionality. So far I found `compact` and `limit`.

This is documented with [`IOContext`](https://docs.julialang.org/en/v1/base/io-network/#Base.IOContext) (and is linked from my new summary in the manual above).

---

<div class="post-metadata">

### Author: ![MatthijsCox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matthijscox/32/42831_2.png) [@MatthijsCox](https://discourse.julialang.org/u/MatthijsCox)
#### Post date: [August 10, 2024, 8:54am UTC](https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790/5 "2024-08-10T08:54:06Z")

</div>

Thanks a lot for your reply! I see that I have to revisit my custom show approach.

But if I want to have a multiline display by default on the REPL, what would you consider the proper approach?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [August 10, 2024, 12:45pm UTC](https://discourse.julialang.org/t/print-vs-two-argument-show-repr-vs-three-argument-show-repr-with-mime-text-plain/117790/6 "2024-08-10T12:45:51Z")

</div>

> [@MatthijsCox](#):
>
> But if I want to have a multiline display by default on the REPL

3-argument `show` is what is called by the REPL display. That’s the multiline version. 2-argument `show` is the `repr(x)` format.
