The documentation for IOContext
says
:compact
output should not contain line breaks
However, this is ignored by arrays and dictionaries:
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> [[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?
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
That’s because nested objects are displayed via 2-argument show
.
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]
1 Like
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.
From the manual, 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
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 […]
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).
The docstring 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:
According to this description (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.
1 Like
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.
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.
5 Likes