# Identical method redefinition suspiciously optimizes runtime and allocations

**URL:** <https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156>\
**Category:** Performance\
**Tags:** memory-allocation, benchmarktools, allocations\
**Created:** [September 7, 2025, 11:42am UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156 "2025-09-07T11:42:14Z")\
**Posts on this page:** 6\
**Page:** 2

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [September 12, 2025, 2:33pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/21 "2025-09-12T14:33:26Z")

</div>

> [@afleming](#):
>
> The behavior can still be reproduced, and the MWE only depends on [StaticArrays.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/StaticArrays).

First off, that’s impressive. Only thing I would suggest is commenting out multiple lines between `#=` and `=#` instead of `#` leading each line to make copy-pasting convenient.

Second, I tried `@code_warntype` right out the gate before any execution, and it appears as type-stable as your reports after benchmarks. However, if we `Cthulhu.@descend` deeper, we run into recursion with changing argument types:

```julia-auto
305 all(f::Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}}::Function, a::SVector{4, SVector{2, Float64}}::StaticArray; dims::Core.Const(Colon())=:)::Bool = _mapreduce(x->f(x)::Bool, &::Core.Const(&), dims::Core.Const(Colon()), true, Size(a::SVector{4, SVector{2, Float64}})::Core.Const(Size(4,)), a::SVector{4, SVector{2, Float64}})
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
   Size(a::SVector{4, SVector{2, Float64}})
 • _mapreduce(x->f(x)::Bool, &::Core.Const(&), dims::Core.Const(Colon()), true, Size(a::SVector{4, SVector{2, Float64}})::Core.Const(Size(4,)), a::SVec…
   ↩
_mapreduce(args::Vararg{Any, N}) where N @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:153
┌ Warning: Inference terminated in an incomplete state due to argument-type changes during recursion

```

despite the ultimate return value of `all` being inferred as `Bool`. The implied recursion isn’t clear because some metaprogramming obscured calls on top of the compromised type information; in other words, it’s hard to pick which lines to manually descend further.

> **Fortunately, \`JET.@reportopt\` automatically ''descends'' into all the calls to filter out instability and dispatch issues, and it spots an explicit recursion becoming unoptimized and runtime-dispatched. It seems to corroborate your comment about \`all(Base.Fix2(...),...)\` being a potential issue for \`point\_inside\_strict\`, a function called in the input function for \`all\` in the benchmarked function.**
>
> ```julia-auto
> julia> @report_opt Euler2D_MWE.is_cell_contained_by(test_cell, test_poly1)
> ═════ 8 possible errors found ═════
> ┌ is_cell_contained_by(cell1::TangentQuadCell_MWE{Float64, 3, 12}, poly::SClosedPolygon{4, Float64}) @ Main.Euler2D_MWE ./REPL[7]:35
> │┌ all(f::Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}}, a::SVector{4, SVector{2, Float64}}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> ││┌ all(f::Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}}, a::SVector{4, SVector{2, Float64}}; dims::Colon) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> │││┌ _mapreduce(::StaticArrays.var"#214#215"{…}, ::typeof(&), ::Colon, ::Bool, ::Size{…}, ::SVector{…}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:153
> ││││┌ _mapfoldl(f::StaticArrays.var"#214#215"{…}, op::typeof(&), dims::Colon, init::Bool, ::Size{…}, a::SVector{…}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:180
> │││││┌ (::StaticArrays.var"#214#215"{Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}}})(x::SVector{2, Float64}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> ││││││┌ (::Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}})(pt::SVector{2, Float64}) @ Main.Euler2D_MWE ./REPL[7]:36
> │││││││┌ point_inside_strict(poly::SClosedPolygon{4, Float64}, pt::SVector{2, Float64}) @ Main.PlanePolygons_MWE ./REPL[6]:71
> ││││││││┌ all(f::Base.Fix2{…}, a::SVector{…}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> │││││││││┌ all(f::Base.Fix2{…}, a::SVector{…}; dims::Colon) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> ││││││││││┌ _mapreduce(::StaticArrays.var"#214#215", ::typeof(&), ::Colon, ::Bool, ::Size{…}, ::SVector{…}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:153
> │││││││││││ runtime dispatch detected: StaticArrays._mapfoldl(%1::StaticArrays.var"#214#215", &, Colon(), %2::Bool, [quote]::Size{(4,)}, %3::SVector{4, Main.PlanePolygons_MWE.Line{Float64}})::Bool
> ││││││││││└────────────────────
> │││││││││┌ all(f::Base.Fix2{…}, a::SVector{…}; dims::Colon) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> ││││││││││ failed to optimize due to recursion: StaticArrays.var"#all#213"(::Colon, ::typeof(all), ::Base.Fix2{…}, ::SVector{…})
> │││││││││└────────────────────
> ││││││││┌ all(f::Base.Fix2{…}, a::SVector{…}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> │││││││││ failed to optimize due to recursion: all(::Base.Fix2{…}, ::SVector{…})
> ││││││││└────────────────────
> │││││││┌ point_inside_strict(poly::SClosedPolygon{4, Float64}, pt::SVector{2, Float64}) @ Main.PlanePolygons_MWE ./REPL[6]:70
> ││││││││ failed to optimize due to recursion: Main.PlanePolygons_MWE.point_inside_strict(::SClosedPolygon{4, Float64}, ::SVector{2, Float64})
> │││││││└────────────────────
> ││││││┌ (::Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}})(pt::SVector{2, Float64}) @ Main.Euler2D_MWE ./REPL[7]:36
> │││││││ failed to optimize due to recursion: (::Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}})(::SVector{2, Float64})
> ││││││└────────────────────
> │││││┌ (::StaticArrays.var"#214#215"{Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}}})(x::SVector{2, Float64}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:305
> ││││││ failed to optimize due to recursion: (::StaticArrays.var"#214#215"{Main.Euler2D_MWE.var"#1#2"{SClosedPolygon{4, Float64}}})(::SVector{2, Float64})
> │││││└────────────────────
> ││││┌ _mapfoldl(f::StaticArrays.var"#214#215"{…}, op::typeof(&), dims::Colon, init::Bool, ::Size{…}, a::SVector{…}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:155
> │││││ failed to optimize due to recursion: StaticArrays._mapfoldl(::StaticArrays.var"#214#215"{…}, ::typeof(&), ::Colon, ::Bool, ::Size{…}, ::SVector{…})
> ││││└────────────────────
> │││┌ _mapreduce(::StaticArrays.var"#214#215"{…}, ::typeof(&), ::Colon, ::Bool, ::Size{…}, ::SVector{…}) @ StaticArrays C:\Users\Benny\.julia\packages\StaticArrays\DsPgf\src\mapreduce.jl:153
> ││││ failed to optimize due to recursion: StaticArrays._mapreduce(::StaticArrays.var"#214#215"{…}, ::typeof(&), ::Colon, ::Bool, ::Size{…}, ::SVector{…})
> │││└────────────────────
> 
> ```

These reports persist after the 0 allocation benchmark. These reports also show up if run fresh after your MWE completed the 0 allocation benchmark. Like `@code_warntype` etc, these packages seem to perform type inference fresh, so it’s still possible it diverges from the actually compiled code. Not great in the exceptional cases like these where state matters.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [September 12, 2025, 4:35pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/22 "2025-09-12T16:35:03Z")

</div>

A workaround is to convert the `SArray` to a `Tuple` before calling `all`:

```julia
all(Tuple(edge_starts(cell_poly)))

```

This avoids the ancient and hacky StaticArrays.jl code, instead relying on `Base` Julia code.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [September 13, 2025, 10:29pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/23 "2025-09-13T22:29:38Z")

</div>

Haven’t examined it, but do you know how introducing that `Tuple` conversion avoids the type-varying recursion issue? It ought to have the same recursive `all` via the input function, right?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [September 13, 2025, 10:39pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/24 "2025-09-13T22:39:35Z")

</div>

Converting to `Tuple` avoids the method of `all` added by StaticArrays.jl.

> [@nsajko](#):
>
> This avoids the ancient and hacky [StaticArrays.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/StaticArrays) code, instead relying on `Base` Julia code.

See:

> <https://github.com/JuliaArrays/StaticArrays.jl/blob/bb20cf40b3910f682cfdd6fb2e9b54f600c09a1b/src/mapreduce.jl#L291-L316>

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [September 14, 2025, 7:11pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/25 "2025-09-14T19:11:53Z")

</div>

> [@nsajko](#):
>
> ancient and hacky [StaticArrays.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/StaticArrays) code

Too quick to disrespect StaticArrays.jl 😅

After a few hours I’m still not able to make a PR to StaticArrays.jl to fix the issue. Some observations:

- The input array to `all` is a nested static array, with static arrays as elements. This complicates the recursion, making inference give up.

- The `all` for `Tuple` does not have to support a `dims` argument, simplifying the problem.

My conclusion, for now, is to convert static arrays to tuples as eagerly as possible.

> [@Benny](#):
>
> do you know how introducing that `Tuple` conversion avoids the type-varying recursion issue?

I guess the important thing about the workaround is that the conversion to tuple happens before any `all(f, c)` call.

---

<div class="post-metadata">

**Author:** ![afleming](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/afleming/32/208443_2.png) [@afleming](https://discourse.julialang.org/u/afleming)\
**Post date:** [September 15, 2025, 12:39am UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/26 "2025-09-15T00:39:19Z")

</div>

> [@nsajko](#):
>
> My conclusion, for now, is to convert static arrays to tuples as eagerly as possible.

Thanks for the help! Converting the `SArray` to a tuple before feeding it to `all` works like a charm. Benchmarks on my machine are even faster, down to 13ns instead of 40ns.

I’ll have to write specializations for boundary polygons that don’t have a compile-time number of vertices, but that’s okay.

[Previous page](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156.md?page=1)
