Print things differently in an array

If I got my custom type MyType I’d like to keep the default printing when showing it isolated, but when in an array I’d like it to only show one of its fields

NWE:

struct MyType
   foo
   bar
end

m = MyType(1, 2)
Base.show(io, m::MyType) = print(io, m.foo)  # will cause both cases to only show the field.
2 Likes

You can use the compact flag of the IOContext, which is set to true when being printed as part of a container. That is, call

if get(io, :compact, false)
    # show inside array
else
    # normal show
end

And/or you can define a 3-argument show(io::IO, ::MIME"text/plain", m::MyType) method for verbose multiline display by the REPL.

2 Likes

I’m doing something wrong

struct MyType
   foo
   bar
end

m = MyType(1, 2)
function Base.show(io, m::MyType)
         if get(io, :compact, false)
           print(io, m.foo)
         else
           Base.show_default(io, m)
         end
end

Base.show(io::IO, ::MIME"text/plain", m::MyType) = Base.show_default(io, m)

julia> m
MyType(1, 2)
# okay
julia> [m]
1-element Vector{MyType}:
1-element Vector{MyType}:
Error showing value of type Vector{MyType}:
ERROR: MethodError: no method matching display(::Vector{MyType})

re-reading that part of the manual, I realized how much words we spent talking about things that are unlikely to be very relevant for someone looking this up

For some reason we delve into the details of:

  • operator precedence and philosophy of repr (i.e. paste result back will evaluate correctly)
  • some “parsing” and metaprogramming constructs (:(...))

And then finally we talk about show(IOContext(stdout, :compact=>true), Polar(3, 4.0)). I think we should just cut straight to :compact => true. Or at the very least, change the order of these two paragraphs.

It’s the difference between a tutorial and a reference, I think, but perhaps the example could be simplified. Will hopefully be improved by:

1 Like

You get more informative output from:

julia> show(stdout, "text/plain", [m])
1-element Vector{MyType}:
ERROR: MethodError: show(::IOContext{IOBuffer}, ::MyType) is ambiguous.

In particular, you should have defined the show method as:

function Base.show(io::IO, m::MyType)

(you were missing the type qualifier for io).

Would be good to improve the error thrown by display here: confusing error thrown by `display` · Issue #54551 · JuliaLang/julia · GitHub

1 Like

that’s very nice! thanks for taking the time to write that summary.

I guess I was mostly questioning the utility of a super specific example (complex number) and also mixing other concepts (repr roundtrip-ability, meta programming) unnecessarily

But even with the correction it doesn’t seem to use the compact path:

struct MyType
   foo
   bar
end

m = MyType(1, 2)

function Base.show(io::IO, m::MyType)
         if get(io, :compact, false)
           print(io, m.foo)
         else
           Base.show_default(io, m)
         end
end

Base.show(io::IO, ::MIME"text/plain", m::MyType) = Base.show_default(io, m)

julia> m
MyType(1, 2)

julia> [m]
1-element Vector{MyType}:
 MyType(1, 2)

Printing array elements apparently uses 3-argument show unless it contains line breaks, so your 2-argument show is not being called. (This was apparently changed in julia#34387, which maybe should have gotten more discussion, grr.)

Also, as commented here, the :compact=>true flag is only set when printing multiple columns. You could use get(io, :typeinfo, Any) === MyType instead, for example.

:tada: that seems to do the trick

struct MyType
    foo
    bar
 end
 
 m = MyType(1, 2)
 
 function Base.show(io::IO, ::MIME"text/plain", m::MyType)
          if get(io, :typeinfo, Any) === MyType
            print(io, m.foo)
          else
            Base.show_default(io, m)
          end
 end
 
 julia> m
 MyType(1, 2)
 
 julia> [m]
 1-element Vector{MyType}:
  1