show and showcompact on custom types

question

#1

I am trying to define a custom type with convenient methods for readout, and having some very basic trouble. I have read the documentation for show with no luck in sorting this out. Defining a method for Base.show(::IO, ::MyType) is simple enough, but when MyType is part of an array, the printout is repeated several times per instance in the array:

struct MyType
  x
end

function Base.show(io::IO, m::MyType) 
  println("instance of MyType:")
  println("x = ", m.x)
end

m = MyType(10)
M = [m, m]

At the console:


julia> m
instance of MyType:
x = 10


julia> M
2-element Array{MyType,1}:
instance of MyType:
x = 10
instance of MyType:
x = 10
 instance of MyType:
x = 10
instance of MyType:
x = 10

 instance of MyType:
x = 10
instance of MyType:
x = 10

If anyone knows the reason for this strange output, any help would be much appreciated!

One suspicion of mine is that this is somehow the result of showcompat, about which the documentation says: “a custom type should test get(io, :compact, false) in its normal show method”. However, I have not been able to find any examples of this in practice, and am not entirely sure what is meant by “test”.

Regardless of whether it is relevant to the problem I am experiencing, I would also like to define and use a showcompact method for some custom types to print nicely in arrays, and so far have not been able to find an example of that anywhere, nor another discussion topic mentioning this.

So if anyone knows the answer to these, or can point me in the right direction, I would be much obliged!


#2

Eg see this example in Base, for Complex.


#3

Thank you!! This is exactly what I was looking for. I have looked through some of the Base code in the past but never come across that.

The result:

function Base.show(io::IO, m::MyType)
    compact = get(io, :compact, false)

    if !compact
        println("Instance of MyType:")
        print("x = ")
    end
        show(io, m.x)
end

julia> m = MyType(10)
Instance of MyType:
x = 10

julia> [m,m]
2-element Array{MyType,1}:
 10
 10

#4

Normally, for multi-line display like this, you don’t use the compact attribute. You define a three-argument show method for text/plain. See the manual section on custom pretty-printing: https://docs.julialang.org/en/stable/manual/types/#Custom-pretty-printing-1


#5

Thanks for the reply @stevengj. I have seen that section of the docs before, but trying to implement it in the past did not produce the results I was expecting:

struct MyType
    x
    y
end


function Base.show(io::IO, m::MyType)
    compact = get(io, :compact, false)

    x = m.x
    y = m.y

    if compact
        print(x, "($y)")
    else
        print(x, " ± $y")
    end
    
end

function Base.show(io::IO, ::MIME"text/plain", m::MyType)
 
    println("Examplary instance of MyType")
    show(io, m)
    
end
julia> m
Examplary instance of MyType
10 ± 21

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

Maybe you can shed some light as to why the array output is so garbled? I was quite surprised actually that using if !compact in the previous method gave me the results I was expecting, but it seemed to work. I’m probably missing something obvious here…


#6

Your show functions need to pass io to print and println. Otherwise you are printing to STDOUT, not to the specified io stream.


#7

Of course! That seems to have worked now. Thanks!

In case anyone stumbles on this with the same problem:

function Base.show(io::IO, m::MyType)
    compact = get(io, :compact, false)

    x = m.x
    y = m.y

    if compact
        print(io, x, "($y)")
    else
        print(io, x, " ± $y")
    end
    
end

function Base.show(io::IO, ::MIME"text/plain", m::MyType)
    println("Examplary instance of MyType")
    show(io, m)
end
julia> m = MyType(10, 11)
Examplary instance of MyType
10 ± 11

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

#8

This is still missing an io argument.


#9

It seems like it would be easier to do

Base.show(io::IO, ::MIME"text/plain", m::MyType) = print(io, "Examplary instance of MyType\n", m.x, " ± ", m.y)
Base.show(io::IO, m::MyType) = print(io, m.x, '(', m.y, ')')

#10

I see. So there’s no reason to explicitly test for compact at all if you do it this way. Thanks for the correction.


#11

I am writing a package where I sometimes want to display a custom type object in a markdown friendly format. In particluar, I want to record a summary of the object’s state to a .md file. For example, the object is a dictionary, and I want to display (or write it to file) as a markdown table, rather than in the usual way. Which variant of show should I be overloading to this?


#12

Base.show(io::IO, ::MIME"text/markdown", m::MyType)


#13

Thanks :slight_smile: