# How to add keyword arguments to extended functions (Base.print)?

**URL:** <https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250>\
**Category:** General Usage\
**Tags:** show, io\
**Created:** [November 10, 2021, 10:03am UTC](https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250 "2021-11-10T10:03:13Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [November 10, 2021, 10:03am UTC](https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250/1 "2021-11-10T10:03:14Z")

</div>

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 ?

```julia
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

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 10, 2021, 12:31pm UTC](https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250/2 "2021-11-10T12:31:26Z")

</div>

> [@sylvaticus](#):
>
> I want to custom the print of my own object, but with an optional keyword argument.

FIrst, you should almost never overload `print` — to customize printing, [you should usually overload `show`](https://docs.julialang.org/en/v1/manual/types/#man-custom-pretty-printing).

Second, have you considered using an [`IOContext` object](https://docs.julialang.org/en/v1/base/io-network/#Base.IOContext) instead? i.e.

```julia
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](https://docs.julialang.org/en/v1/base/io-network/#Base.IOContext-Tuple%7BIO,%20Pair%7D) like `:compact` that may be what you want.

Fourth, as explained in the [custom pretty-printing manual](https://docs.julialang.org/en/v1/manual/types/#man-custom-pretty-printing), 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`).

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 10, 2021, 12:38pm UTC](https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250/3 "2021-11-10T12:38:53Z")

</div>

> [@sylvaticus](#):
>
> I already know that keyword arguments can not be used for dispatching, but can keyword arguments be added to extended functions ?

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.)

> [@sylvaticus](#):
>
> `print(a;what="minimal") # error, keyword argument "what" not found`

You got this error because you overloaded `print(io, x::Foo)` but not `print(x::Foo)`. You would need to define:

```julia
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.

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [November 10, 2021, 4:09pm UTC](https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250/4 "2021-11-10T16:09:06Z")

</div>

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:

```julia
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 :-/ 

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 10, 2021, 5:19pm UTC](https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250/5 "2021-11-10T17:19:43Z")

</div>

> [@sylvaticus](#):
>
> 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.

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.

---

<div class="post-metadata">

**Author:** ![Jean\_Michel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jean_michel/32/8282_2.png) [@Jean\_Michel](https://discourse.julialang.org/u/Jean_Michel)\
**Post date:** [November 11, 2021, 7:29am UTC](https://discourse.julialang.org/t/how-to-add-keyword-arguments-to-extended-functions-base-print/71250/6 "2021-11-11T07:29:30Z")

</div>

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)`
