Skip to content

clarify show interface for containers #40030

@xitology

Description

@xitology

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    collectionsData structures holding multiple items, e.g. sets

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions