I want to custom the print of my own object, but with an optional keyword argument. However when I then call my customised print
using the keyword argument Julia tells me it couldn’t find it. I already know that keyword arguments can not be used for dispatching, but can keyword arguments be added to extended functions ?
using Revise
module testPrint
export Foo, print
struct Foo{T}
x::String
y::T
end
end
using .testPrint
a = Foo("aa",10)
print(a) # "normal" print
import Base.print, Base.println
function print(io::IO, o::Foo; what="all")
if(what == "all")
print("This is $(o.x) and this is $(o.y). Correct?")
else
print("This is $(o.x), stop")
end
end
print(a) # object-specific print, fine
print(a;what="minimal") # error, keyword argument "what" not found
FIrst, you should almost never overload print
— to customize printing, you should usually overload show
.
Second, have you considered using an IOContext
object instead? i.e.
function Base.show(io::IO, o::Foo)
what = get(io, :what, "all")
...
end
println(IOContext(stdout, :what => "minimal"), o)
This has the advantage that it is composable. For example, suppose that you have an array of Foo
objects — by attaching :what
to the io
object, you can print
the array and it will pass through to the underlying show
calls for the individual elements.
Third, the IOContext
interface already defines some standard keywords like :compact
that may be what you want.
Fourth, as explained in the custom pretty-printing manual, if you just want single-line vs. multi-line (verbose) pretty-pretting options, you should typically define a 2-argument show
for the former and a 3-argument show(io, "text/plain", x)
for the latter (which is then used by e.g. the REPL display
).
4 Likes
To answer this question: yes, absolutely, when you define your own print
function for your ::Foo
type, you can add whatever arguments you want, change the argument order, add keywords, etcetera. As long as there is at least one non-keyword argument of type ::Foo
, Julia can disambiguate the dispatch (and it is not type piracy).
(Normally, when overloading a function you try not to change the API too much, to aid in usability, but this is not technically required.)
You got this error because you overloaded print(io, x::Foo)
but not print(x::Foo)
. You would need to define:
Base.print(x::Foo; kws...) = print(stdout, x; kws...)
in order to pass keyword arguments through from the 1-argument print
.
But, as I said above, normally you should not overload print
to customize pretty printing.
3 Likes
I am sorry. The “manual” is too terse and I am completely lost in print/show/display/IOContext/TTY…
All I need is print() to default to print the long representation of the type (a confusion matrix report in the real application) with a keyword argument to specify which parts of the report to print.
This still doesn’t work:
module testPrint
export Foo
struct Foo{T}
x::String
y::T
end
function Base.show(io::IO, o::Foo;what="all")
print(io, "Foo($(o.x), $(o.y))")
end
function Base.show(io::IO, ::MIME"text/plain", o::Foo; what="all")
if(what == "all")
print(io,"This is $(o.x) and this is $(o.y). Correct?")
else
print(io,"This is $(o.x), stop")
end
return nothing
end
Base.show(mimetype::MIME"text/plain", o::Foo; what="all") = Base.show(stdout,mimetype, o; what=what)
Base.show(o::Foo; what="all") = Base.show(stdout,o; what=what)
Base.print(o::Foo;what="all") = show(stdout,"text/plain",o;what=what)
Base.println(o::Foo;what="all") = begin show(stdout,"text/plain",o;what=what); print("\n") end
end
using .testPrint
a = Foo("aa",10)
print(a) # same keyword argument not found :-/
You overload show
to change how everything in Julia (print
, repr
, display
, …) displays instances of your type. But then you are better off using an IOContext
if you want to perform additional customization in a composable way.
If you just want a custom output function that you call occasionally, but you don’t want to affect other code that tries to output instances of your type, I would give it a different name, printreport(io::IO, x::MyType; someoptions....)
and then do whatever you want.
2 Likes
What I think would be useful is versions of print
and println
with keywords arguments, so that
print(io,x,y;k...)
would be defined as print(IOContext(io,k...),x,y)
. This way you would just have to type
print(io,x,y;limit=true,compact=true)
instead of print(IOContext(io,:limit=>true,:compact=>true),x,y)
1 Like