Let’s say I have a type with an abbreviated show method for the type itself (for shortened stacktraces).
struct Blarg{X,Y}
x::X
y::Y
end
Base.show(io::IO, ::Type{Blarg{X,Y}}) where {X,Y} = print(io, "Blarg{$X,...}")
Base.show(io::IO, ::MIME"text/plain", ::Type{Blarg{X,Y}}) where {X,Y} = print(io, "Blarg{$X,$Y}")
Now if I define a function that uses type parameter annotations, I get an error. What is happening here? Why does it say X not defined?
julia> f(blarg::Blarg{X,Y}) where {X,Y} = blarg.x + blarg.y
f (generic function with 1 method)
julia> methods(f)
# 1 method for generic function "f":
[1] Error showing value of type Base.MethodList:
ERROR: UndefVarError: X not defined
Stacktrace:
[1] show(io::IOContext{IOBuffer}, #unused#::
SYSTEM (REPL): showing an error caused an error
ERROR: UndefVarError: X 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
Note that if the function definition doesn’t use type parameter annotations, there isn’t a problem:
julia> new_f(blarg::Blarg) = blarg.x
new_f (generic function with 1 method)
julia> methods(new_f)
# 1 method for generic function "new_f":
[1] new_f(blarg::Blarg) in Main at REPL[6]:1
instead of Type{Blarg{X,Y}} and it works (I don’t know exactly what that Type could be doing there, but I didn’t use it for a similar function before).
The Type is important here. I’m not trying to control the printing for the instance of the type, I’m trying to control the printing for the type itself when it’s inside of stacktraces.
@tomerarnon Ah, that’s unfortunate. The combination of DifferentialEquations.jl’s type parameterizations and ComponentArrays.jl’s value-as-type axis types make stack traces pretty useless without some type of abridged printing.
@marius311 Thanks for the tip on the aliasing solution, I’ll have to check that out. Hopefully it offers some distinction between MIME types because it’s important to be able to see a fully-printed type when calling typeof directly. This wouldn’t be a strict aliasing situation.
Never played with it so don’t know if it does, but if it doesn’t, another option is to use @isdefined in your custom show to avoid errors. You’ll have to play with in what scenarios things come in as defined or not, its a bit of a mystery to me still.
You can overload the internal function which is used by stacktrace printing. No guarantee this will keep working, but it ought not to change anything else, like methods(f), at the moment:
julia> function Base.print_type_stacktrace(io, type; color=:normal)
str = first(sprint(show, type, context=io), 20) # <-- only change, could add ... etc.
i = findfirst('{', str)
if isnothing(i) || !get(io, :backtrace, false)::Bool
printstyled(io, str; color=color)
else
printstyled(io, str[1:prevind(str,i)]; color=color)
printstyled(io, str[i:end]; color=:light_black)
end
end
julia> map(+, (((((1,),),),),))
ERROR: MethodError: ...
Stacktrace:
[1] map(f::typeof(+), t::Tuple{Tuple{Tuple{Tu) # <-- trimmed here
@ Base ./tuple.jl:213