When writing some methods for show for types in a package, I was wondering if there is any mechanism (or package) for reusing show methods for fields but nesting the indentation.
Eg suppose a type prints as
This is a Foo with 3x2 elements.
[1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0]
and a type Bar prints as
This is a Bar with critical value 0.7
Then for a type Baz
struct Bar
foo::Foo
bar::Bar
end
is there an organized way to write a show method that
reuses show code for the fields,
indents the fields.
Eg
This is a Bar with fields
This is a Foo with 3x2 elements.
[1.0 1.0 1.0; 1.0 1.0 1.0; 1.0 1.0 1.0]
This is a Bar with critical value 0.7
Solutions I have thought of:
use something other than indentation, eg •,
pass around the current indentation as an optional 3rd argument of show, defaulting to 0.
I’m not aware of a generic solution for indentation, but the official way to pass arguments to show is to use IOContext. Eg. show(IOContext(indent=get(io, :indent, 0)+2), mime, child_object). See also this example for displaying a tree. It works, but I do dearly miss CL’s special variables.
When I’ve need to do this in the past I’ve added an indent field to
[IOContext]
(https://docs.julialang.org/en/stable/stdlib/io-network/#Base.IOContext)
that gets added to whenever we need to nest another level. It won’t work
with Base types or types from other packages, but within a package you
can use it for all your types that could be nested within each other.
-s
If you want a kludgey half-solution that works even for types you don’t own, you can have your types make and pass down an IOBuffer instead of the io arg when they recurse into show on their children, then re-emit each line of that buffer with indentation added to the front. It looks sort of like this:
function Base.show(io::IO, mime, x::Bar)
println(io, "This is a Bar with fields")
buffer = IOBuffer()
for c in x.children
show(buffer, mime, c)
for line in split(String(take!(buffer)), "\n")
println(io, " ", line)
end
end
end
Other types won’t be able to add new levels of indentation, so e.g. Dicts might be a touch ugly, but at least now even multiline children will be properly indented inside your own types.
(Yes, the performance is horrible, almost certainly outright quadratic in the depth unless IOBuffer and String and take! are all doing some deep cooperative pointer-shuffling magic, but it’s pretty-printing for human inspection so N is like eight at most, lol. )