# \[ANN\] SimpleTypePrint.jl: customize how types are displayed

**URL:** <https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115>\
**Category:** Package Announcements\
**Tags:** announcement\
**Created:** [December 20, 2020, 5:26am UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115 "2020-12-20T05:26:02Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![MrVPlusOne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrvplusone/32/20400_2.png) [@MrVPlusOne](https://discourse.julialang.org/u/MrVPlusOne)\
**Post date:** [December 20, 2020, 5:26am UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/1 "2020-12-20T05:26:02Z")

</div>

Julia’s type system is awesome, but sometimes the types we encountered are very large and can be just too hard to read. That’s why I made this simple package [SimpleTypePrint.jl](https://github.com/MrVPlusOne/SimpleTypePrint) to let you customize how types are displayed. Currently, it supports the following changes compared to `Base.show(::Type)`:

- Merging nested where clauses
- Limiting the maximal type depth to dispaly
- Displaying type names without module prefixes
- Renaming type variables with conflicting names

Hope you find this useful && any feedback is welcome!

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [December 20, 2020, 5:29am UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/2 "2020-12-20T05:29:23Z")

</div>

The nested where clause one is something we definitely should have in `Base`. Would you be willing to write a PR? Conflicting names might also belong, but I’m less certain.

---

<div class="post-metadata">

**Author:** ![MrVPlusOne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrvplusone/32/20400_2.png) [@MrVPlusOne](https://discourse.julialang.org/u/MrVPlusOne)\
**Post date:** [December 20, 2020, 5:53am UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/3 "2020-12-20T05:53:36Z")

</div>

> The nested where clause one is something we definitely should have in `Base` . Would you be willing to write a PR?

Sure, I’d be glad to write a PR for that.

> Conflicting names might also belong, but I’m less certain.

I do see some code to rename conflicting type variables in the Base, but it seems like it’s somehow buggy and not working properly.

---

<div class="post-metadata">

**Author:** ![thofma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thofma/32/1691_2.png) [@thofma](https://discourse.julialang.org/u/thofma)\
**Post date:** [December 20, 2020, 2:14pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/4 "2020-12-20T14:14:04Z")

</div>

This is overloading Base.show for types, right? This used to be discouraged, since it led to some internal errors, see e.g. [https://github.com/JuliaArrays/StaticArrays.jl/pull/769](https://github.com/JuliaArrays/StaticArrays.jl/pull/769) or [https://github.com/JuliaLang/julia/issues/22363](https://github.com/JuliaLang/julia/issues/22363). Did something change in this regard? Is it now safe to redefine Base.show on types?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 20, 2020, 3:41pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/5 "2020-12-20T15:41:41Z")

</div>

It’s actually much more extensive than those examples, as it [redefines `show` for `Type`](https://github.com/MrVPlusOne/SimpleTypePrint/blob/038b954f21e8bfea6ab1905a53560cbce8c6ffb8/src/SimpleTypePrint.jl#L172), not a specific one.

---

<div class="post-metadata">

**Author:** ![MrVPlusOne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrvplusone/32/20400_2.png) [@MrVPlusOne](https://discourse.julialang.org/u/MrVPlusOne)\
**Post date:** [December 20, 2020, 5:23pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/6 "2020-12-20T17:23:35Z")

</div>

That’s a concern that I also had! That’s why overriding `Base.show` is optional—SimpleTypePrint will only do so if you call the provided `config_type_display` function. You can also just manually call the `show_type` function without modifying `Base.show`.

Also as pointed out by @Tamas_Papp, calling `config_type_display` refines `show` for all types instead of a specific one, so its behavior should be more consistent (and hence safer?) than overriding `show` for some specific types. My understanding is that this can still potentially break other libraries if they depend on the specific behavior of the current `Base.show` implementation (e.g., show where clauses separately). But so far I haven’t encountered such cases yet (My limited experience: I have been using `config_type_display` with 30ish other libraries inside VSCode for the past month).

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 21, 2020, 8:59am UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/7 "2020-12-21T08:59:37Z")

</div>

I am wondering if there is a non-pirating way to do these kind of things though — maybe using the display stack with a wrapper type?

Here is a quick proof of concept (which needs some extra work though):

```julia
struct MyIO <: IO
    io::IO
end

function Base.show(io::MyIO, M::MIME"text/plain", ::Type{T}) where T
    print(io.io, "custom $T")
end

Base.show(io::MyIO, M::MIME"text/plain", x) = show(io.io, M, x)

pushdisplay(TextDisplay(MyIO(stdout)))

```

Then

```julia
julia> 1 + 1
2
julia> Float64
custom Float64

```

---

<div class="post-metadata">

**Author:** ![MrVPlusOne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrvplusone/32/20400_2.png) [@MrVPlusOne](https://discourse.julialang.org/u/MrVPlusOne)\
**Post date:** [December 21, 2020, 6:21pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/8 "2020-12-21T18:21:27Z")

</div>

Interesting idea! I tried this and it seems to be working for types printed to stdout. (BTW, for `print` to work, we will also need to define `Base.write(s::SimpleTypeIO, x::UInt8) = write(s.io, x)`.) However, one main usage of this for me is to have simpler types shown in stacktraces. Any idea of how to make this work for stacktraces without pirating?

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [December 21, 2020, 6:57pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/9 "2020-12-21T18:57:49Z")

</div>

For stack traces, there is a function `print_type_stacktrace` which handles the colour printing of types. Overloading that to shorten things doesn’t seem likely to break anything else, and might be worth doing in general. Also discussed a bit in [this thread](https://discourse.julialang.org/t/these-stack-traces-are-out-of-control/47162). (Edit – maybe this is the issue: [https://github.com/JuliaLang/julia/issues/36517](https://github.com/JuliaLang/julia/issues/36517) .)

I don’t think that would affect method error printing. It would be nice if that could be abbreviated to enough levels to show the mismatch, somehow. If `f` only accepts some particular kind of AbstractArray, and I call it with a tuple (of complicated objects), then the mismatch is at the outermost layer.

---

<div class="post-metadata">

**Author:** ![MrVPlusOne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrvplusone/32/20400_2.png) [@MrVPlusOne](https://discourse.julialang.org/u/MrVPlusOne)\
**Post date:** [December 21, 2020, 8:38pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/10 "2020-12-21T20:38:57Z")

</div>

> [@mcabbott](#):
>
> I don’t think that would affect method error printing. It would be nice if that could be abbreviated to enough levels to show the mismatch, somehow. If `f` only accepts some particular kind of AbstractArray, and I call it with a tuple (of complicated objects), then the mismatch is at the outermost layer.

I like this idea. It sounds like to implement this, we will need a way to compute the (minimal?) differences between two given types. Intellij IDEA actually [does this](https://blog.jetbrains.com/scala/2019/07/24/intellij-scala-plugin-2019-2-functional-code-highlighting-fine-grained-type-diff-case-clause-completion-build-server-protocol-and-more/#fine-grained-type-diff) for Scala type mismatch. Is there a similar functionality already implemented in Julia? I imagine it could be tricky to implement this for the general cases since Julia supports union/intersection types with constraints on type parameters.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [December 21, 2020, 8:43pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/11 "2020-12-21T20:43:49Z")

</div>

Agree it seems tricky, I don’t know of such a function, but it may exist.

I guess the easy part would be to trim the types of arguments which _do_ match. In your [readme’s example](https://github.com/MrVPlusOne/SimpleTypePrint#motivation) the first argument is already quite long, but since it matches, we probably don’t need to see all the detail.

---

<div class="post-metadata">

**Author:** ![MrVPlusOne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrvplusone/32/20400_2.png) [@MrVPlusOne](https://discourse.julialang.org/u/MrVPlusOne)\
**Post date:** [December 21, 2020, 9:06pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/12 "2020-12-21T21:06:14Z")

</div>

Hmm… Would always trimming matched arguments to the minimal level be too aggressive and accidentally hide important information from the user? For example, that might lead to errors like

`no methods match +(Array{...}, Float64)`,

where the compiler displays the closest candidate as `+(Array{...}, Int)`, but the true source of the error is actually caused by the first argument having the incorrect type `Array{Float64}`.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [December 21, 2020, 9:17pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/13 "2020-12-21T21:17:20Z")

</div>

Right, one would need to think about this carefully. If there are several partial matches, then it tries to display a few, and presumably they should all constrain the level of detail. I don’t know the list of partial matches is generated, nor how it gets trimmed for printing:

```julia
julia> f(x::Array{Int}, y::Int) = "Int"; f(x::Array{Float64}, y::Float64) = "Floats";

julia> f([1,2,3], 4.5)
ERROR: MethodError: no method matching f(::Vector{Int64}, ::Float64)
Closest candidates are:
  f(::Array{Int64, N} where N, ::Int64) at REPL[41]:1
  f(::Array{Float64, N} where N, ::Float64) at REPL[41]:1

julia> [1,2,3] + 4.5
ERROR: MethodError: no method matching +(::Vector{Int64}, ::Float64)
For element-wise addition, use broadcasting with dot syntax: array .+ scalar
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:597
  +(::Base.TwicePrecision, ::Number) at twiceprecision.jl:267
  +(::Array, ::Array...) at arraymath.jl:43
  ...

```

---

<div class="post-metadata">

**Author:** ![MrVPlusOne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrvplusone/32/20400_2.png) [@MrVPlusOne](https://discourse.julialang.org/u/MrVPlusOne)\
**Post date:** [December 21, 2020, 9:29pm UTC](https://discourse.julialang.org/t/ann-simpletypeprint-jl-customize-how-types-are-displayed/52115/14 "2020-12-21T21:29:56Z")

</div>

Yeah, I agree. I think it’s safer to use type difference to compute the _minimal_ display level that is needed to highlight the type mismatch, but determining the _maximal_ display level (that is as small as possible) can be much trickier.
