Weird error after defining Base.show method for custom DataType

I don’t know if defining a new method of Base.show for a custom type (the type itself and not it instances) is something that someone shouldn’t do, but basically: i have a type Operator{T} where T is a Symbol, and instead of showing Operator{:(=)}, for example, every time the type gets printed in the console, i want it to show Operator{=}, so i defined a new method of Base.show, and it works, however, when the type should be printed in a exception, i get “showing an error caused an error”. I’ll let the code speak for itself:

julia> macro Operator_str(str)
           sym = QuoteNode(Symbol(str))
           Expr(:curly, :Operator, sym)
       end
@Operator_str (macro with 1 method)

julia> struct Operator{T}
           args::Vector
       end

julia> equals = Operator"="([:a, :b])
Operator{:(=)}([:a, :b])

julia> Operator"*"
Operator{:*}

julia> function Base.show(io::IO, ::Type{Operator{T}}) where {T}
           print(io, "Operator{$T}")
       end

julia> equals
Operator{=}([:a, :b])

julia> Operator"*"
Operator{*}

julia> Operator"|"()
ERROR: MethodError: no method matching Operator{|}()
Stacktrace:
 [1] top-level scope
   @ REPL[8]:1
SYSTEM (REPL): showing an error caused an error
ERROR: UndefVarError: T not defined
Stacktrace:
  [1] show(io::IOContext{IOBuffer}, #unused#::
SYSTEM (REPL): caught exception of type UndefVarError while trying to handle a nested exception; giving up

Also, when running the code outside the REPL i get this:

julia ./test.jl
equals = Operator{:(=)}([:a, :b])
equals = Operator{=}([:a, :b])
Operator"|" = Operator{|}
ERROR: LoadError: MethodError: no method matching Operator{|}()
Stacktrace:
 [1] top-level scope
   @ C:\Users\jorge\dev\test.jl:20ERROR: UndefVarError: T not defined
Stacktrace:
  [1] show(io::IOContext{IOBuffer}, #unused#::fatal: error thrown and no exception handler available.
UndefVarError(var=:T)
jl_undefined_var_error at /cygdrive/c/buildbot/worker/package_win64/build/src\rtutils.c:132
show at C:\Users\jorge\dev\test.jl:14
show_typeparams at .\show.jl:640
show_datatype at .\show.jl:1011
show_datatype at .\show.jl:989 [inlined]
_show_type at .\show.jl:889
jfptr__show_type_38169.clone_1 at C:\Users\jorge\AppData\Local\Programs\Julia-1.7.2\lib\julia\sys.dll (unknown line)
show at .\show.jl:881
jfptr_show_33170.clone_1 at C:\Users\jorge\AppData\Local\Programs\Julia-1.7.2\lib\julia\sys.dll (unknown line)
#sprint#426 at .\strings\io.jl:112
sprint##kw at .\strings\io.jl:108 [inlined]
#print_type_stacktrace#485 at .\show.jl:2399
print_type_stacktrace at .\show.jl:2399
jfptr_print_type_stacktrace_31920.clone_1 at C:\Users\jorge\AppData\Local\Programs\Julia-1.7.2\lib\julia\sys.dll (unknown line)
#show_tuple_as_call#484 at .\show.jl:2380
show_tuple_as_call##kw at .\show.jl:2353
jfptr_show_tuple_as_callYY.YY.kw_46476.clone_1 at C:\Users\jorge\AppData\Local\Programs\Julia-1.7.2\lib\julia\sys.dll (unknown line)
show_spec_linfo at .\stacktraces.jl:244
print_stackframe at .\errorshow.jl:709
print_stackframe at .\errorshow.jl:685
#show_full_backtrace#834 at .\errorshow.jl:574
show_full_backtrace##kw at .\errorshow.jl:565 [inlined]
show_backtrace at .\errorshow.jl:769
#showerror#813 at .\errorshow.jl:90
showerror##kw at .\errorshow.jl:87
unknown function (ip: 000000005f01f123)
show_exception_stack at .\errorshow.jl:866
display_error at .\client.jl:104
unknown function (ip: 000000005f013764)
display_error at .\client.jl:107
unknown function (ip: 000000005f0131e0)
jl_apply at /cygdrive/c/buildbot/worker/package_win64/build/src\julia.h:1788 [inlined]
jl_f__call_latest at /cygdrive/c/buildbot/worker/package_win64/build/src\builtins.c:757
#invokelatest#2 at .\essentials.jl:716 [inlined]
invokelatest at .\essentials.jl:714 [inlined]
_start at .\client.jl:497
jfptr__start_21275.clone_1 at C:\Users\jorge\AppData\Local\Programs\Julia-1.7.2\lib\julia\sys.dll (unknown line)
jl_apply at /cygdrive/c/buildbot/worker/package_win64/build/src\julia.h:1788 [inlined]
true_main at /cygdrive/c/buildbot/worker/package_win64/build/src\jlapi.c:559
jl_repl_entrypoint at /cygdrive/c/buildbot/worker/package_win64/build/src\jlapi.c:701
mainCRTStartup at /cygdrive/c/buildbot/worker/package_win64/build/cli\loader_exe.c:42
BaseThreadInitThunk at C:\Windows\System32\KERNEL32.DLL (unknown line)
RtlUserThreadStart at C:\Windows\SYSTEM32\ntdll.dll (unknown line)

The workaround that i found for this problem is:

julia> function Base.show(io::IO, type::Type{<:Operator})
           T = first(type.parameters)
           print(io, "Operator{$T}")
       end

julia> equals
Operator{=}([:a, :b])

julia> Operator"|"
Operator{|}

julia> Operator"|"()
ERROR: MethodError: no method matching Operator{|}()
Closest candidates are:
  Operator{T}(::Any) where T at REPL[2]:2
Stacktrace:
 [1] top-level scope
   @ REPL[7]:1

So my question is: is this a bug or i shouldn’t define Base.show for a specific DataType?

Yes. Can’t find the issue atm, but, as you can see, doing that can be pretty dangerous.

1 Like

Thanks for your answer. Another question, wouldn’t be helpful if Julia detects when a user tries to do something like this, so the user can know that he/she shouldn’t do that?