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 ?
export Foo, print
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?")
print("This is $(o.x), stop")
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
Second, have you considered using an
IOContext object instead? i.e.
function Base.show(io::IO, o::Foo)
what = get(io, :what, "all")
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.
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
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
But, as I said above, normally you should not overload
print to customize pretty printing.
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:
function Base.show(io::IO, o::Foo;what="all")
print(io, "Foo($(o.x), $(o.y))")
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?")
print(io,"This is $(o.x), stop")
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
a = Foo("aa",10)
print(a) # same keyword argument not found :-/
show to change how everything in Julia (
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.
What I think would be useful is versions of
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