# How to detect in \`show\` that you are computing display for the REPL?

**URL:** <https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951>\
**Category:** New to Julia\
**Created:** [December 23, 2018, 10:45pm UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951 "2018-12-23T22:45:52Z")\
**Posts on this page:** 11\
**Page:** 2

<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:** [December 24, 2018, 1:40pm UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/21 "2018-12-24T13:40:03Z")

</div>

Thanks, but I tried:

```julia
function Base.show(io::IO, m::MIME"text/plain", a::AbstractArray{<:Cyc,N}) where N
    invoke(show, Tuple{IO, MIME"text/plain", AbstractArray{Any,N}}, 
           IOContext(io, :repl=>true), m, a)
end

Base.show(io::IO, c::Cyc) = print(io,format(c,
                 get(io, :repl=>true, false) ? :fancy : :plain))

```

and got

```julia
julia> l=[E(i)+E(j) for i in 1:4, j in 1:4]
Error showing value of type Array{Cyc{Int64},2}:
ERROR: invoke: argument type error
Stacktrace:
 [1] show(::IOContext{REPL.Terminals.TTYTerminal}, ::MIME{Symbol("text/plain")}, ::Array{Cyc{Int64},2}) at /home/jmichel/julia/Gapjm/src/Cycs.jl:268
 [2] display(::REPL.REPLDisplay, ::MIME{Symbol("text/plain")}, ::Any) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:131
 [3] display(::REPL.REPLDisplay, ::Any) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:135
 [4] display(::Any) at ./multimedia.jl:287
 [5] #invokelatest#1 at ./essentials.jl:697 [inlined]
 [6] invokelatest at ./essentials.jl:696 [inlined]
 [7] print_response(::IO, ::Any, ::Any, ::Bool, ::Bool, ::Any) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:154
 [8] print_response(::REPL.AbstractREPL, ::Any, ::Any, ::Bool, ::Bool) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:139
........

```

(it goes on 20 stack frames)

---

<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:** [December 24, 2018, 2:10pm UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/22 "2018-12-24T14:10:02Z")

</div>

Sorry, it should be `AbstractArray{<:Any,N}`; I fixed it in my post above.

---

<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:** [December 24, 2018, 2:28pm UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/23 "2018-12-24T14:28:28Z")

</div>

Thanks. I marked your reply as giving the answer. However, as Bennedich noted, this solves one of the cases of REPL display. One would have to do the same overloading job with other data structures containing `Cyc`s, for instance:

```julia
julia> a=Dict(1=>E(3),2=>E(4))
Dict{Int64,Cyc{Int64}} with 2 entries:
  2 => E(4)
  1 => E(3)

```

where I would like to see:

```julia
julia> a=Dict(1=>E(3),2=>E(4))
Dict{Int64,Cyc{Int64}} with 2 entries:
  2 => ζ₄
  1 => ζ₃

```

It would be nice if whenever printing at the repl, the IOContext would include `:repl=>true`

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [December 25, 2018, 12:14am UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/24 "2018-12-25T00:14:35Z")

</div>

If you want `repr` to create parsable output, and want this to work with any container type, I would still consider overloading `repr` and use the context keyword we discussed earlier. It seems to me that this solves all of your problems?

The solution above seems far from optimal since you’ll need to add new code for every `Cyc` container type you’ll be using, so in a software engineering sense you are introducing technical debt (not solving the problem once and for all).

Sample code:

```julia
struct Cyc n::Int end

E(n) = Cyc(n)

format(c, style) = style == :plain ? "E($(c.n))" : "ζ$(c.n)"

Base.show(io::IO, c::Cyc) = print(io, format(c, get(io, :style, :fancy)))
Base.repr(x) = repr(x; context = :style => :plain)

```

Testing it:

```julia
julia> c = E(4)
ζ4

julia> v = [E(i+j) for i in 1:4, j in 1:4]
4×4 Array{Cyc,2}:
 ζ2 ζ3 ζ4 ζ5
 ζ3 ζ4 ζ5 ζ6
 ζ4 ζ5 ζ6 ζ7
 ζ5 ζ6 ζ7 ζ8

julia> d = Dict(1=>E(3), 2=>E(4))
Dict{Int64,Cyc} with 2 entries:
  2 => ζ4
  1 => ζ3

julia> println("My cyc is $c and my dict is $d")
My cyc is ζ4 and my dict is Dict(2=>ζ4,1=>ζ3)

julia> repr(c)
"E(4)"

julia> repr(v)
"Cyc[E(2) E(3) E(4) E(5); E(3) E(4) E(5) E(6); E(4) E(5) E(6) E(7); E(5) E(6) E(7) E(8)]"

julia> repr(d)
"Dict(2=>E(4),1=>E(3))"

```

---

<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:** [December 25, 2018, 12:32am UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/25 "2018-12-25T00:32:01Z")

</div>

Thanks. Maybe it was not clear to you, but I understood quite well your solution before and saw that it works.  
The reason I went on is to explore what well-informed people like stevengj would say about the language design.

It seems my problem is a quite general one, and I would like to see what solution would be considered “the right way” by the language designers. I was told “do not overload `repr`”. Your proposal is a particular way  
to build a “serialize\_to\_string” function. Now why does this function does not yet exist? Is it not because  
people think that `repr` (without an additional argument) should be this function?

My self, I think my proposal (make so that any output call from the REPL adds a marker to the IOContext)  
could be a good design. I hope that if any other commiters visits this thread, they would give their opinion.

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [December 25, 2018, 1:02am UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/26 "2018-12-25T01:02:53Z")

</div>

Got it. Good questions. If there’s no better alternative, I am also curious how “overload every possible container of your type” would be preferred over “do not overload repr” in your case.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 25, 2018, 7:53am UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/27 "2018-12-25T07:53:07Z")

</div>

FYI, following `IOContext` are provided to `show` for the case the object in question is in a container (see below for the code to check it):

| | `:typeinfo` | `:limit` | `:compact` | `:color` |
| --- | --- | --- | --- | --- |
| `display([T()])` | `T` | `true` | | `true` |
| `show([T()])` | `T` | | `true` | `true` |
| `repr([T()])` | `T` | | `true` | |
| `display(Dict(:a=>T()))` | | `true` | `true` | `true` |
| `show(Dict(:a=>T()))` | `T` | | `true` | `true` |
| `repr(Dict(:a=>T()))` | `T` | | `true` | |

From this, it seems that differentiating `display` (i.e., REPL) and `repr` can be done by simply looking at `:limit` in `show(::IO, ::T)`. See also: [I/O and Network · The Julia Language](https://docs.julialang.org/en/v1/base/io-network/#Base.IOContext-Tuple%7BIO,Pair%7D)

I also add that the Style Guide seems to explicitly discourage `AbstractArray{<:Cyc}` solution:

> **Don’t overload methods of base container types**
> 
> It is possible to write definitions like the following:
> 
> ```julia
> show(io::IO, v::Vector{MyType}) = ...
> 
> ```
> 
> This would provide custom showing of vectors with a specific new element type. While tempting, this should be avoided. The trouble is that users will expect a well-known type like Vector() to behave in a certain way, and overly customizing its behavior can make it harder to work with.
> 
> — [Style Guide · The Julia Language](https://docs.julialang.org/en/v1.2-dev/manual/style-guide/#Don't-overload-methods-of-base-container-types-1)

…although it does not quite apply to your case, since you just use the container’s `show` almost as-is.

* * *

> [@Jean\_Michel](#):
>
> It would be nice if whenever printing at the repl, the IOContext would include `:repl=>true`

Aren’t you just need to check if `repr` or not, rather than REPL-or-not? If so, I think an alternative approach would be to add a public API `show(::IO, ::MIME"application/julia", ::MyType)` which is called from `repr` if it exists. (I know this MIME is not super legit but [`julia` actually already “knows” it](https://github.com/JuliaLang/julia/pull/18441).)

* * *

> **Code to check the table**
>
> ```julia
> julia> struct LogIO end
> 
> julia> logio_log = []
> 0-element Array{Any,1}
> 
> julia> function logio_show(io, mime)
> push!(logio_log, ("mime", mime))
> push!(logio_log, ("io isa IOContext", io isa IOContext))
> if io isa IOContext
> push!(logio_log, ("io.dict", io.dict))
> end
> print(io, "LogIO")
> end
> logio_show (generic function with 1 method)
> 
> julia> Base.show(io::IO, mime::MIME"text/plain", ::LogIO) =
> logio_show(io, mime)
> 
> julia> Base.show(io::IO, ::LogIO) =
> logio_show(io, nothing)
> 
> julia> empty!(logio_log)
> display([LogIO()])
> logio_log
> 1-element Array{LogIO,1}:
> LogIO
> 9-element Array{Any,1}:
> ("mime", nothing)
> ("io isa IOContext", true)
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:typeinfo=>LogIO,:module=>Main,:limit=>true,:color=>true))
> ("mime", nothing)
> ("io isa IOContext", true)
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:typeinfo=>LogIO,:module=>Main,:limit=>true,:color=>true))
> ("mime", nothing)
> ("io isa IOContext", true)
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:typeinfo=>LogIO,:module=>Main,:limit=>true,:color=>true))
> 
> julia> empty!(logio_log)
> show([LogIO()])
> logio_log
> LogIO[LogIO]3-element Array{Any,1}:
> ("mime", nothing)                                                                                                
> ("io isa IOContext", true)                                                                                       
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:SHOWN_SET=>LogIO[LogIO],:compact=>true,:typeinfo=>LogIO,:color=>true))
> 
> julia> empty!(logio_log)
> repr([LogIO()])
> logio_log
> 3-element Array{Any,1}:
> ("mime", nothing)
> ("io isa IOContext", true)
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:SHOWN_SET=>LogIO[LogIO],:compact=>true,:typeinfo=>LogIO))
> 
> julia> empty!(logio_log)
> display(Dict(:a=>LogIO()))
> logio_log
> Dict{Symbol,LogIO} with 1 entry:
> :a => LogIO
> 3-element Array{Any,1}:
> ("mime", nothing)                                                                                                
> ("io isa IOContext", true)                                                                                       
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:compact=>true,:SHOWN_SET=>Dict(:a=>LogIO),:module=>Main,:limit=>true,:color=>true))
> 
> julia> empty!(logio_log)
> show(Dict(:a=>LogIO()))
> logio_log
> Dict(:a=>LogIO)3-element Array{Any,1}:
> ("mime", nothing)                                                                                                
> ("io isa IOContext", true)                                                                                       
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:typeinfo=>LogIO,:compact=>true,:compact=>true,:typeinfo=>Pair{Symbol,LogIO},:SHOWN_SET=>Dict(:a=>LogIO),:color=>true))
> 
> julia> empty!(logio_log)
> repr(Dict(:a=>LogIO()))
> logio_log
> 3-element Array{Any,1}:
> ("mime", nothing)                                                                                                
> ("io isa IOContext", true)                                                                                       
> ("io.dict", Base.ImmutableDict{Symbol,Any}(:typeinfo=>LogIO,:compact=>true,:compact=>true,:typeinfo=>Pair{Symbol,LogIO},:SHOWN_SET=>Dict(:a=>LogIO)))
> 
> ```

---

<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:** [December 25, 2018, 9:02am UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/28 "2018-12-25T09:02:26Z")

</div>

Thank you very much for your analysis. It seems that checking for ‘:limit’ is a perfectly practical solution now. Of course, the question is if it works by design or by chance; in this last case a more stable API would be useful. As you say, the question is distinguishing `repr` from other environments where the formatting is (presumably) for display purposes. It would be good to adopt and document a solution. Another formatting  
environment for which a marker should be documented/agreed upon is building strings for TeXing.

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [December 25, 2018, 11:55am UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/29 "2018-12-25T11:55:52Z")

</div>

`:limit` is used to truncate long output, so this implementation means to use fancy output whenever output is truncated. If the goal is to distinguish `repr` from other forms of display, this would not fully work, since for example print output and exceptions would still use `repr` style output.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 25, 2018, 6:38pm UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/30 "2018-12-25T18:38:37Z")

</div>

I agree that using `:limit` is not fully satisfactory. But it kind of makes sense because `:limit => true` means you need to limit output and give up conveying all the information contents for the sake of simplicity. In this case, using unicode to “compress” information sounds reasonable.

---

<div class="post-metadata">

**Author:** ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)\
**Post date:** [December 28, 2018, 4:45pm UTC](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951/31 "2018-12-28T16:45:02Z")

</div>

> [@Jean\_Michel](#):
>
> Of course, the question is if it works by design or by chance

I would say (as the person who introduced IOContext), that it was by-design and indicates whether the output is for interactive-consumption (and thus may truncate or eliminate information) or offline analysis (more machine parsable, avoiding discarding information).

[Previous page](https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951.md?page=1)
