# Why does \`show\` for arrays and dictionaries ignore \`:compact\`?

**URL:** https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159
**Category:** Internals & Design
**Tags:** array, dictionary, show
**Created:** [August 13, 2024, 10:57pm UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159 "2024-08-13T22:57:01Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)
#### Post date: [August 13, 2024, 10:57pm UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159/1 "2024-08-13T22:57:02Z")

</div>

The documentation for `IOContext` says

> `:compact` output should not contain line breaks

However, this is ignored by arrays and dictionaries:

```julia
julia> show(IOContext(stdout, :compact => true), MIME"text/plain"(), [1, 2])
2-element Vector{Int64}:
 1
 2

julia> show(IOContext(stdout, :compact => true), MIME"text/plain"(), Dict(1 => 2, 3 => 4))
Dict{Int64, Int64} with 2 entries:
  3 => 4
  1 => 2

```

On the other hand, an array or dictionary inside one of these types _is_ displayed in a compact format:

```julia
julia> [[1, 2], Dict(1 => 2, 3 => 4)]
2-element Vector{Any}:
 [1, 2]
 Dict(3 => 4, 1 => 2)

```

As far as I understand, this would be a typical use case for `:compact`. This makes it even more surprising that this flag is ignored for these types. Is it for historical reasons? Would it make sense to add that feature?

---

<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 13, 2024, 11:32pm UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159/2 "2024-08-13T23:32:45Z")

</div>

> [@matthias314](#):
>
> this is ignored by arrays and dictionaries:

You are using 3-argument `show`, which can always be multi-line; the prohibition on line breaks only applies to 2-argument `show`.

That should be clarified in the docs: [clarify that :compact prohibition on line breaks is for 2-arg show by stevengj · Pull Request #55489 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/55489)

> [@matthias314](#):
>
> On the other hand, an array or dictionary inside one of these types _is_ displayed in a compact format:

That’s because nested objects are displayed via 2-argument `show`.

```julia
julia> show(IOContext(stdout, :compact => true), [1, 2])
[1, 2]
julia> show(stdout, [1, 2]) # 2-arg show for arrays doesn't use line breaks anyway
[1, 2]
julia> println([1, 2]) # calls show(io, [1, 2]))
[1, 2]

```

---

<div class="post-metadata">

### Author: ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)
#### Post date: [August 13, 2024, 11:53pm UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159/3 "2024-08-13T23:53:55Z")

</div>

Thanks for the clarification. What’s the rationale for restricting the “no line break” rule for `:compact` to the two-argument `show`? I understand that the purpose of the three-argument version is to be human-readable. It seems to me that the nesting rule you mention breaks that.

Also, if I implement `show` for my own type (with unconstrained type parameters), then it’s unclear which other types (from who knows which package) should participate in the nesting rule. Wouldn’t it be cleaner if also the three-argument version of `show` respects `:compact`? Then I could simply display every field with `:compact`, no matter what type it is.

ADDED: One could ask what “compact output” for the three-argument version of `show` is supposed to mean at all if line breaks are allowed. I would say that avoiding line breaks is the first step to make the output more compact.

---

<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 14, 2024, 12:41am UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159/4 "2024-08-14T00:41:59Z")

</div>

> [@matthias314](#):
>
> What’s the rationale for restricting the “no line break” rule for `:compact` to the two-argument `show`?

[From the manual](https://docs.julialang.org/en/v1/manual/types/#man-custom-pretty-printing), the whole purpose of 3-argument `show` from the beginning was for verbose, potentially multi-line display in interactive environments:

> […] sometimes one wants both a verbose multi-line printing format, used for displaying a single object in the REPL and other interactive environments, and also a more compact single-line format used for [`print`](https://docs.julialang.org/en/v1/base/io-network/#Base.print) or for displaying the object as part of another object (e.g. in an array). Although by default the `show(io, z)` function is called in both cases, you can define a _different_ multi-line format for displaying an object by overloading a three-argument form of `show` that takes the `text/plain` MIME type as its second argument […]

> [@matthias314](#):
>
> Also, if I implement `show` for my own type (with unconstrained type parameters), then it’s unclear which other types (from who knows which package) should participate in the nesting rule.

Easy: normally, you should use 2-argument `show` (or functions that call it, like `print`) for _all_ nested objects. 3-argument `show` is normally only called at the top level (e.g. by `display` of a REPL result).

---

<div class="post-metadata">

### Author: ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)
#### Post date: [August 14, 2024, 2:04am UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159/5 "2024-08-14T02:04:05Z")

</div>

> [@stevengj](#):
>
> the whole purpose of 3-argument `show` from the beginning was for verbose, potentially multi-line display in interactive environments

The [docstring](https://docs.julialang.org/en/v1/base/io-network/#Base.show-Tuple%7BIO,%20Any%7D) for `show` takes a somewhat different point of view:

> The representation used by `show` […] should be parseable Julia code when possible. […] For a more verbose human-readable text output for objects of type `T`, define `show(io::IO, ::MIME"text/plain", ::T)` in addition. Checking the `:compact` `IOContext` key […] of `io` in such methods is recommended, since some containers show their elements by calling this method with `:compact => true`.

From this perspective, it doesn’t feel ideal to switch between the two versions because the parseable and the human-readable form of some element may differ a lot.

I still find the idea appealing that `show` for arrays and dictionaries pays attention to `:compact`. For example, the 3-argument `show` for arrays with `:compact` could display something in the form of 2-argument `show`, but with 3-argument `show` applied to each element. 2-argument `show` with `:compact` could leave out the spaces: `[1,2,3]` instead of `[1, 2, 3]`. That would make it easier to write `show` for new containers. Currently it’s more complicated:

> [@stevengj](#):
>
> you should use 2-argument `show` […] for _all_ nested objects. 3-argument `show` is normally only called at the top level

According to [this description](https://github.com/JuliaLang/julia/issues/40030) (hopefully not outdated), the 3-argument versions of `show` for arrays and dictionaries don’t do that. They first call 3-argument `show` for an element. If the output contains line breaks, they call the 2-argument version. It would be nice to avoid this for every new container type.

---

<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 14, 2024, 2:10am UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159/6 "2024-08-14T02:10:20Z")

</div>

> [@matthias314](#):
>
> They first call 3-argument `show` for an element. If the output contains line breaks, they call the 2-argument version. It would be nice to avoid this for every new container type.

Yes, I’m not happy with that hack, I think it was a mistake.

I seem to remember that it was added because of some date I/O change, but I’d have to check the git blame.

---

<div class="post-metadata">

### Author: ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)
#### Post date: [August 14, 2024, 5:43am UTC](https://discourse.julialang.org/t/why-does-show-for-arrays-and-dictionaries-ignore-compact/118159/7 "2024-08-14T05:43:30Z")

</div>

I will say I don’t like the mixing of parsable vs. pretty display, the two are currently mixed with the 2/3 arg show methods.

This is something I’ve run into when I want to have:

- a multi-line pretty display
- an inline pretty display
- a parsable display

And (2), the “inline pretty display” is hard to have (particularly when printed as a part of other objects) due to the way 2/3 arg `show` calling is mixed. At this point I almost think it would be better to have different function names for the 2/3 arg `show` methods to more clearly delineate the “pretty” and “parsable” cases.
