# Can I make type alias show up in a stack trace?

**URL:** <https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360>\
**Category:** General Usage\
**Created:** [August 25, 2022, 8:28pm UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360 "2022-08-25T20:28:06Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [August 25, 2022, 8:28pm UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/1 "2022-08-25T20:28:06Z")

</div>

I’ve seen a lot of style guides that suggest being sparing with closures. Which is concerning, because I use a ton of closures. Part of the motivation for that advice seems to be because stack traces are hard to learn from when they have elements on `[5] (::var"#1#2")(::Float64)` or whatever in them.

I unfortunately need to make a lot of closures that are not at top level scope, so it isn’t super easy to make a normal struct and then dynamically add methods to it. But even inside my function bodies I can of course make anonymous structs and give them methods, like this:

```julia
test = (a=1, b="yes", c=1.0, f=log)
const MyStruct = typeof(test)
eval_f(s::MyStruct, x) = s.f(x)

```

I’m hoping that this may at least be used to get more information in stack traces. But when I call `eval_f(test, -1.0)`, my stacktrace gives me:

```julia
ERROR: DomainError with -1.0:
log will only return a [...].
Stacktrace:
[...]
 [4] eval_f(s::NamedTuple{(:a, :b, :c, :f), Tuple{Int64, String, Float64, typeof(log)}}, x::Float64)
   @ Main ./REPL[4]:1
[...]

```

Is there any way for me to make this line in the stacktrace instead say `eval_f(s::MyStruct, x::Float64)` for methods and type aliases that are not created at top level? It seems sort of unlikely, but I thought I’d ask.

---

<div class="post-metadata">

**Author:** ![ikirill](https://avatars.discourse-cdn.com/v4/letter/i/43a26b/32.png) [@ikirill](https://discourse.julialang.org/u/ikirill)\
**Post date:** [August 26, 2022, 6:16am UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/2 "2022-08-26T06:16:16Z")

</div>

No, because it’s not really an alias, as it would be in Haskell. `MyStruct` is a constant value, like a normal variable, that evaluates at function definition to `NamedTuple{...etc}`, so julia isn’t aware of `MyStruct` any more when it’s defining the method `eval_f`, or when it’s printing the stack trace.

I think the closest you can get is:

```julia
Base.@kwdef struct MyStruct{A,B,C,F}; a::A; b::B; c::C; f::F; end
eval_f(s::MyStruct, x) = ...

# or, to be able to call it using the syntax s(x)
# which you can't do with a NamedTuple

function (s::MyStruct)(x)
    s.f(x)
end

```

I haven’t run this example, it might be a little bit wrong if it happens that julia doesn’t figure out how to call `s.f(x)` efficiently, but I think it should. If not sure, you’d need to check with `@profile` and `@descend`.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [August 26, 2022, 7:34am UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/3 "2022-08-26T07:34:22Z")

</div>

Type aliases are correctly printed in stack traces:

```julia
julia> map(1, [1, 2])
...
 [4] map(f::Int64, A::Vector{Int64})
...

```

However, Julia only displays aliases defined in the same module as the original type. That’s why your NamedTuple alias is not shown.

---

<div class="post-metadata">

**Author:** ![ikirill](https://avatars.discourse-cdn.com/v4/letter/i/43a26b/32.png) [@ikirill](https://discourse.julialang.org/u/ikirill)\
**Post date:** [August 26, 2022, 8:14am UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/4 "2022-08-26T08:14:58Z")

</div>

Did that change at some point? I might be wrong about this, but on 1.7.3:

```julia
module M

struct A
    a
end

const B = A

function f(b::B)
    Base.show_backtrace(stderr, backtrace())
    b.a
end

end

M.f(M.A(0))

```

```julia
Stacktrace:
 [1] f(b::Main.M.A)
...

```

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [August 26, 2022, 3:09pm UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/5 "2022-08-26T15:09:10Z")

</div>

Thanks to you both for the observations and clarifications. I think what I was hoping to do is just a bit more doomed than I thought. I managed to put together a working example of what I was thinking about, but I needed to use `GeneralizedGenerated.jl` and my stack traces are not better than just using a closure, in my opinion. Here is the example:

```julia
using GeneralizedGenerated

struct AnonStr{Name,T}
  nt::T
end

# This is just an example, but in my actual application I was hoping to add
# methods to MOI's functions.
function objective end

# If you just make this @generated, you get an error that there's a closure
# inside. But I don't get it, because at the time of compilation isn't the type
# ProbT fully known? I see in the GG docs that functions become closures,
# but I guess I just don't have an intuition for why that limitation exists.
@gg function example(a1::T1, a2::T2, a3::T3) where{T1, T2, T3}
  NT = NamedTuple{(:a1, :a2, :a3), Tuple{T1, T2, T3}}
  ProbT = AnonStr{:MyProblem, NT}
  quote
    myproblem = $ProbT((a1=a1, a2=a2, a3=a3))
    function objective(m::$ProbT, x) 
      log(x/m.nt.a1)*m.nt.a2 + m.nt.a3
    end
    objective(myproblem, 1.1) # change to -1.1 to see stacktrace.
  end
end

# Not only does this seem sort of weird because now every new call to example
# has the potential to re-define a method, but it doesn't even create those
# methods persistently and the stack traces are not helpful:
example(1,2,3)
length(methods(objective)) # zero

```

My actual application is that I want to use `MathOptInterface` to interact with optimizers like Ipopt and KNITRO, but for some reasons I don’t really want to get into I don’t want to use `JuMP` or other existing tools. But I think I’ve basically just sort of discovered-by-doing why they all use macros to define various things like the objective and constraints and stuff as a way to avoid having a million closures.

Anyways, thanks again for giving my question a read and sharing thoughts!

---

<div class="post-metadata">

**Author:** ![ederag](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ederag/32/4106_2.png) [@ederag](https://discourse.julialang.org/u/ederag)\
**Post date:** [August 26, 2022, 4:16pm UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/6 "2022-08-26T16:16:20Z")

</div>

Not a direct answer to your question, but functors (callables that hold data) might be a solution;  
there is an example in this issue (fixed):  
[https://github.com/JuliaNLSolvers/Optim.jl/issues/853](https://github.com/JuliaNLSolvers/Optim.jl/issues/853)

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [August 26, 2022, 4:28pm UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/7 "2022-08-26T16:28:05Z")

</div>

Thanks for the link! I actually didn’t think of that option (good to know there is a real name, by the way—I’ve just been referring to them with “structs with methods” for a while). In playing around it seems like I still need to use `@eval` and some extra generated functions package. But if I can find some option that isn’t crazy and gives me nicer stacktraces than closures I’ll update this thread.

---

<div class="post-metadata">

**Author:** ![Jollywatt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jollywatt/32/202198_2.png) [@Jollywatt](https://discourse.julialang.org/u/Jollywatt)\
**Post date:** [August 26, 2022, 9:57pm UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/8 "2022-08-26T21:57:39Z")

</div>

```julia
julia> test = (a=1, b="yes", c=1.0, f=log)
(a = 1, b = "yes", c = 1.0, f = log)

julia> const MyStruct = typeof(test)
MyStruct

julia> Base.show(io::IO, ::Type{MyStruct}) = print(io, "MyStruct")

julia> [test]
1-element Vector{MyStruct}:
 (a = 1, b = "yes", c = 1.0, f = log)

julia> test + 1
ERROR: MethodError: no method matching +(::MyStruct, ::Int64)
…

```

---

<div class="post-metadata">

**Author:** ![ederag](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ederag/32/4106_2.png) [@ederag](https://discourse.julialang.org/u/ederag)\
**Post date:** [August 27, 2022, 6:48am UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/9 "2022-08-27T06:48:02Z")

</div>

in a fresh REPL

```julia
julia> test = (a=1, b="yes", c=1.0, f=log)
(a = 1, b = "yes", c = 1.0, f = log)

julia> const MyStruct = typeof(test)
NamedTuple{(:a, :b, :c, :f), Tuple{Int64, String, Float64, typeof(log)}}

```

so `MyStruct` is still a `NamedTuple`.

Overloading `Base.show(io::IO, ::Type{MyStruct})` is thus type piracy  
(there nothing specific to the writer,  
since `MyStruct` is just a binding to a type that belongs to `Base`)  
All `NamedTuple{(:a, :b, :d, :f), Tuple{Int64, String, Float64, typeof(log)}}`,  
even those from another package would now display the same `MyStruct`.  
(probability is low here, but you see the danger of this approach in general)

```julia
 # same type, but constructed through Base, not MyStruct
julia> [(a=2, b="yes", c=2.0, f=log)]
1-element Vector{MyStruct}:
 (a = 2, b = "yes", c = 2.0, f = log)

# changed first key to 'd'
julia> [(d=2, b="yes", c=2.0, f=log)] 
1-element Vector{NamedTuple{(:d, :b, :c, :f), Tuple{Int64, String, Float64, typeof(log)}}}:
 (d = 2, b = "yes", c = 2.0, f = log)

```

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [August 27, 2022, 8:03pm UTC](https://discourse.julialang.org/t/can-i-make-type-alias-show-up-in-a-stack-trace/86360/10 "2022-08-27T20:03:52Z")

</div>

Thanks to you both! I see your point about type piracy. Considering that I actually need to do all of this inside of functions this is just starting to seem like a bad idea. But in case anybody else stumbles on this thread, here is the “solution” to what I was hoping to do:

```julia
# @noinline just to make the stack trace show the method.
@noinline eval_f(str, x) = str.f(x)

function fun(x)
  myobject = (a=1, b="yes", c=1.0, f=log)
  myobjectT = typeof(myobject)
  @eval Base.show(io::IO, ::Type{$myobjectT}) = print(io, "MyCoolStruct")
  eval_f(myobject, x)
end

```

I haven’t looked at the performance implications of doing something like this and it is almost certainly not really advisable just to get a little more information in a stacktrace. Also, I see no reason why I couldn’t just do this to a closure type directly and then get a named closure in the stacktrace.

Anyways. Thanks to all who chimed in to help!
