# Why does JET seemingly not flag dynamic dispatch in this string interpolation?

**URL:** <https://discourse.julialang.org/t/why-does-jet-seemingly-not-flag-dynamic-dispatch-in-this-string-interpolation/112603>\
**Category:** Performance\
**Tags:** type-stability, jet\
**Created:** [April 6, 2024, 11:02am UTC](https://discourse.julialang.org/t/why-does-jet-seemingly-not-flag-dynamic-dispatch-in-this-string-interpolation/112603 "2024-04-06T11:02:45Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [April 6, 2024, 11:02am UTC](https://discourse.julialang.org/t/why-does-jet-seemingly-not-flag-dynamic-dispatch-in-this-string-interpolation/112603/1 "2024-04-06T11:02:45Z")

</div>

```julia
julia> using LinearAlgebra, Cthulhu, JET

julia> D = Diagonal(rand(2));

julia> @descend setindex!(D, 2, 1, 2) # Cthulhu
setindex!(D::Diagonal, v, i::Int64, j::Int64) @ LinearAlgebra ~/.julia/juliaup/julia-1.11.0-alpha2+0.x64.linux.gnu/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:188
188 function setindex!(D::Diagonal{Float64, Vector{Float64}}::Diagonal, v::Int64, i::Int64::Int, j::Int64::Int)::Int64
189 @boundscheck checkbounds(D::Diagonal{Float64, Vector{Float64}}, i::Int64, j::Int64)
190 if (i::Int64 == j::Int64)::Bool
191 @inbounds D::Diagonal{Float64, Vector{Float64}}.diag::Vector{Float64}[i::Int64] = v::Int64
192 elseif !(iszero(v::Int64)::Bool)::Bool
193 throw(ArgumentError("cannot set off-diagonal entry ($i::Int64, $j::Int64) to a nonzero value ($v::Int64)"::Any)::Any)
194 end
195 return v::Int64
196 end
Select a call to descend into or ↩ to ascend. [q]uit. [b]ookmark.
Toggles: [w]arn, [h]ide type-stable statements, [t]ype annotations, [s]yntax highlight for Source/LLVM/Native, [j]ump to source always.
Show: [S]ource code, [A]ST, [T]yped code, [L]LVM IR, [N]ative code
Actions: [E]dit source code, [R]evise and redisplay
 • %5 = checkbounds(::Diagonal{Float64, Vector{Float64}},::Int64,::Int64)::Any
    i::Int64 == j::Int64
   D::Diagonal{Float64, Vector{Float64}}.diag
   %10 = setindex!(::Vector{Float64},::Int64,::Int64)::Any
   iszero(v::Int64)
    !iszero(v::Int64)::Bool
   runtime "cannot set off-diagonal entry ($i::Int64, $j::Int64) to a nonzero value ($v::Int64)"
   runtime ArgumentError("cannot set off-diagonal entry ($i::Int64, $j::Int64) to a nonzero value ($v::Int64)"::Any)
   ↩

julia> @report_opt setindex!(D, 2, 1, 2) # JET
No errors detected

julia> VERSION
v"1.11.0-alpha2"

```

Cthulhu marks the string interpolation in the `ArgumentError` message as a runtime dispatch, but JET doesn’t report this (although it does report similar calls elsewhere).

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [April 6, 2024, 12:23pm UTC](https://discourse.julialang.org/t/why-does-jet-seemingly-not-flag-dynamic-dispatch-in-this-string-interpolation/112603/2 "2024-04-06T12:23:04Z")

</div>

Without having run the code, I believe runtime dispatch is collected by `@report_call` when using JET. Does that report what you want?

Kind regards

---

<div class="post-metadata">

**Author:** ![aviatesk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aviatesk/32/7610_2.png) [@aviatesk](https://discourse.julialang.org/u/aviatesk)\
**Post date:** [April 6, 2024, 1:09pm UTC](https://discourse.julialang.org/t/why-does-jet-seemingly-not-flag-dynamic-dispatch-in-this-string-interpolation/112603/3 "2024-04-06T13:09:37Z")

</div>

The reason for this behavior is due to the `skip_unoptimized_throw_blocks::Bool=true` setting. The Julia compiler deliberately skips inference on code paths that are known to `throw` (for better latency), and JET follows suit by not reporting runtime dispatches on such code paths. If you switch to `skip_unoptimized_throw_blocks=false`, you should see the errors:

```julia
julia> @report_opt skip_unoptimized_throw_blocks=false setindex!(D, 2, 1, 2)
═════ 2 possible errors found ═════
┌ setindex!(D::Diagonal{Float64, Vector{Float64}}, v::Int64, i::Int64, j::Int64) @ LinearAlgebra /Users/aviatesk/julia/julia2/usr/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:193
│ runtime dispatch detected: string("cannot set off-diagonal entry (", i::Int64, ", ", j::Int64, ") to a nonzero value (", v::Int64, ")")::Any
└────────────────────
┌ setindex!(D::Diagonal{Float64, Vector{Float64}}, v::Int64, i::Int64, j::Int64) @ LinearAlgebra /Users/aviatesk/julia/julia2/usr/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:193
│ runtime dispatch detected: LinearAlgebra.ArgumentError(%49::Any)::Any
└────────────────────

```

See also: [Optimization Analysis · JET.jl](https://aviatesk.github.io/JET.jl/dev/optanalysis/#JET.OptAnalyzer)

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [April 6, 2024, 1:53pm UTC](https://discourse.julialang.org/t/why-does-jet-seemingly-not-flag-dynamic-dispatch-in-this-string-interpolation/112603/4 "2024-04-06T13:53:22Z")

</div>

I’m a bit confused, as the following does report similar dynamic dispatches in the error paths. Is this related to inlining, and are the throw blocks being optimized here?

```julia
julia> using LinearAlgebra, JET

julia> D = Diagonal(rand(2));

julia> @report_opt D * D
═════ 4 possible errors found ═════
┌ *(Da::Diagonal{Float64, Vector{Float64}}, Db::Diagonal{Float64, Vector{Float64}}) @ LinearAlgebra /cache/build/builder-amdci4-1/julialang/julia-release-1-dot-11/usr/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:304
│┌ _muldiag_size_check(A::Diagonal{Float64, Vector{Float64}}, B::Diagonal{Float64, Vector{Float64}}) @ LinearAlgebra /cache/build/builder-amdci4-1/julialang/julia-release-1-dot-11/usr/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:284
││┌ (::LinearAlgebra.var"#throw_dimerr#251")(::Diagonal{Float64, Vector{Float64}}, nA::Int64, mB::Int64) @ LinearAlgebra /cache/build/builder-amdci4-1/julialang/julia-release-1-dot-11/usr/share/julia/stdlib/v1.11/LinearAlgebra/src/diagonal.jl:282
│││┌ string(::String, ::Int64, ::String, ::Int64) @ Base ./strings/io.jl:189
││││┌ print_to_string(::String, ::Int64, ::String, ::Int64) @ Base ./strings/io.jl:150
│││││┌ _unsafe_take!(io::IOBuffer) @ Base ./iobuffer.jl:494
││││││┌ wrap(::Type{Array}, m::MemoryRef{UInt8}, l::Int64) @ Base ./array.jl:3101
│││││││ failed to optimize due to recursion: wrap(::Type{Array}, ::MemoryRef{UInt8}, ::Int64)
││││││└────────────────────
│││││┌ print_to_string(::String, ::Int64, ::String, ::Vararg{Any}) @ Base ./strings/io.jl:143
││││││ runtime dispatch detected: Base._str_sizehint(%17::Any)::Int64
│││││└────────────────────
│││││┌ print_to_string(::String, ::Int64, ::String, ::Vararg{Any}) @ Base ./strings/io.jl:148
││││││ runtime dispatch detected: print(%59::IOBuffer, %97::Any)::Any
│││││└────────────────────
│││││┌ string(::String, ::Int64, ::String, ::Tuple{Int64}, ::String, ::Int64, ::String, ::Int64, ::String) @ Base ./strings/io.jl:189
││││││ failed to optimize due to recursion: string(::String, ::Int64, ::String, ::Tuple{Int64}, ::String, ::Int64, ::String, ::Int64, ::String)
│││││└──

```

---

<div class="post-metadata">

**Author:** ![aviatesk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aviatesk/32/7610_2.png) [@aviatesk](https://discourse.julialang.org/u/aviatesk)\
**Post date:** [April 23, 2024, 1:13pm UTC](https://discourse.julialang.org/t/why-does-jet-seemingly-not-flag-dynamic-dispatch-in-this-string-interpolation/112603/5 "2024-04-23T13:13:54Z")

</div>

The throw block deoptimization might not kick in under certain conditions, particularly when the method being analyzed still keeps a positive effect, so that’s possible.

Having said that this deoptimization does complicate the compiler’s behavior, so it’s slated for removal in the future.
