# 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:** 20\
**Page:** 1

<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 7, 2025, 11:42am UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/1 "2025-09-07T11:42:14Z")

</div>

I am using Revise.jl to work on a package for my research, and am noticing that “revising” a file to _identical code with different variable names_ causes a function to stop allocating.

I am not sure how many details others will need to help me diagnose the issue, but my workflow is as follows:

1. Run a script using Julia and the `-i` flag. `startup.jl` consists only of `using Revise`.
2. The script loads some data files, as well as BenchmarkTools.jl and Plots.jl
3. Benchmark some functions that need to be allocation-free (for performance reasons).

The offending function is:

```julia
function is_cell_contained_by(cell1, poly)
    cell_poly = cell_boundary_polygon(cell1) # this is an SVector
    return all(edge_starts(cell_poly)) do pt # edge_starts returns an SVector
        return PlanePolygons.point_inside_strict(poly, pt) # this does not allocate
    end
end

```

And benchmarking it:

```julia-auto
julia> @benchmark Euler2D.is_cell_contained_by($test_cell, $test_poly)
BenchmarkTools.Trial: 10000 samples with 709 evaluations per sample.
 Range (min … max): 180.385 ns … 51.612 μs ┊ GC (min … max): 0.00% … 99.40%
 Time (median): 194.587 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 237.031 ns ± 556.060 ns ┊ GC (mean ± σ): 8.90% ± 8.09%

   ▃▇█▅▄▁ ▂▂▂▃▃▂▂▁▁ ▂
  ███████████▇▇▆▆▆▆▄▃▅▃▁▁▄▄▁▄▁▃▄▁▁▁▇██████████▇▆▆▃▄▃▁▁▁▃▄▁▃▃▄▃▄ █
  180 ns Histogram: log(frequency) by time 437 ns <

 Memory estimate: 464 bytes, allocs estimate: 5.

```

Well, that’s odd. Edit the file defining `is_cell_contained_by(...)` and let Revise.jl do its magic. I change the function to:

```julia
function is_cell_contained_by(cell1, poly)
    cell_polys = cell_boundary_polygon(cell1)
    return all(edge_starts(cell_polys)) do pt
        return PlanePolygons.point_inside_strict(poly, pt)
    end
end

```

Notice that _only_ the variable name has changed: `cell_poly` → `cell_polys`. Benchmark it again:

```julia-auto
julia> @benchmark Euler2D.is_cell_contained_by($test_cell, $test_poly)
BenchmarkTools.Trial: 10000 samples with 985 evaluations per sample.
 Range (min … max): 53.646 ns … 108.297 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 57.632 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 57.934 ns ± 2.129 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

                  ▂▁▁▁▄▆█▇▇▅▁▁ ▁ ▁▁▂▁ ▁▁ ▂▁ ▂
  ▄█▆▇▃▃▁▁▁▆▇▃▅▇▅▇█████████████████▆▆▅▄▆▇███████████▇▆▆▆▅▄▅▆▆▆ █
  53.6 ns Histogram: log(frequency) by time 63.8 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

This is the behavior I expect… but I do not know why I have to force Revise.jl to pick up on the new function every time I run the script.

Is there a cache I can clear somewhere? Should I kill every running Julia process on my machine and try again? I am absolutely baffled, and I hope that I’m just falling into a common Revise.jl trap, rather than doing something truly stupid.

---

<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 7, 2025, 12:02pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/2 "2025-09-07T12:02:01Z")

</div>

I did try:

1. removing the `~/.julia/compiled/` to force everything to be compiled again. The behavior persists.
2. running the script and the benchmark without Revise loaded, which yields _only_ the allocating version of the benchmark with no way to trigger optimization.

---

<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 7, 2025, 2:50pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/3 "2025-09-07T14:50:59Z")

</div>

> [@afleming](#):
>
> Run a script using Julia and the `-i` flag  
> …  
> let [Revise.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/Revise) do its magic.

How exactly? Revise isn’t documented to track input scripts at command lines e.g. `julia -i script.jl`.

Disappearing allocations like that is bizarre though, I’d want to know if there’s some unstable compiler optimization going on. However, that’s impossible to tell from the outside without the source code (everything, startup.jl, the script, the packages, the benchmark) and a reproducible process.

---

<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 10, 2025, 3:55pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/4 "2025-09-10T15:55:00Z")

</div>

> [@Benny](#):
>
> How exactly? Revise isn’t documented to track input scripts at command lines e.g. `julia -i script.jl`.

Ah, I apologize. I edit the source file in a local package.

I will try to reproduce the behavior without the full details of my current project when I have some spare time. Thanks!

---

<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 10, 2025, 4:49pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/5 "2025-09-10T16:49:43Z")

</div>

Do you see the same effect if you redefine the method without Revise? You can do so (approximately, may need edits) with

```julia-auto
@eval Euler2D function is_cell_contained_by(cell1, poly)
    cell_polys = cell_boundary_polygon(cell1)
    return all(edge_starts(cell_polys)) do pt
        return PlanePolygons.point_inside_strict(poly, pt)
    end
end

```

If you see the same effect, then Revise isn’t a cause, which could vastly simplify reproduction.

---

<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 10, 2025, 5:08pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/6 "2025-09-10T17:08:20Z")

</div>

Started up a my normal workflow (loaded a data file, loaded the Euler2D module). Source code for `is_cell_contained_by` is:

```julia
function is_cell_contained_by(cell1, poly)
    cell_polys = cell_boundary_polygon(cell1)
    return all(edge_starts(cell_polys)) do pt
        return PlanePolygons.point_inside_strict(poly, pt)
    end
end

function is_cell_contained_by(cell1, cell2::FVMCell)
    return is_cell_contained_by(cell1, cell_boundary_polygon(cell2))
end

```

The `test_poly1` object is not a subtype of FVMCell, so the first method should be evaluated:

```julia-auto
julia> test_poly1 isa FVMCell
false

```

Benchmarking:

```julia-auto
julia> @benchmark Euler2D.is_cell_contained_by($(sim1.cells[1][1]), $test_poly1)
BenchmarkTools.Trial: 10000 samples with 728 evaluations per sample.
 Range (min … max): 177.935 ns … 22.936 μs ┊ GC (min … max): 0.00% … 98.91%
 Time (median): 190.871 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 255.046 ns ± 440.140 ns ┊ GC (mean ± σ): 13.28% ± 8.12%

  ▃▅▇█▆▅▃▂ ▁▁▂▃▃▃▃▂▂▁ ▂
  ██████████▇▇▆▇▅▆▆▄▅▅▆▅▅▄▆▄▅▅▅▄▅▅▄▃▅▄▃▄▄▄▆▇███████████▇▇▆▅▃▄▃▃ █
  178 ns Histogram: log(frequency) by time 399 ns <

 Memory estimate: 464 bytes, allocs estimate: 5.

julia> @eval Euler2D function is_cell_contained_by(cell1, poly)
           cell_polys = cell_boundary_polygon(cell1)
           return all(edge_starts(cell_polys)) do pt
               return PlanePolygons.point_inside_strict(poly, pt)
           end
       end
is_cell_contained_by (generic function with 2 methods)

julia> @benchmark Euler2D.is_cell_contained_by($(sim1.cells[1][1]), $test_poly1)
BenchmarkTools.Trial: 10000 samples with 989 evaluations per sample.
 Range (min … max): 46.894 ns … 499.099 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 49.862 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 50.416 ns ± 8.729 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

                    ▁▂▄▅▇██▆▄▃▃▂▂▂▂▂▃▃▄▃▃▂▁▁ ▁▁ ▂
  ▅██▇▅▆▆▆▇▇▆▃▂▂▅▆▇██████████████████████████▇█████▇▇▇▆▆▇▇▇▇▆▆ █
  46.9 ns Histogram: log(frequency) by time 54.3 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<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 10, 2025, 5:17pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/7 "2025-09-10T17:17:32Z")

</div>

Am I right to assume you didn’t load Revise via startup.jl? If you had, can you replicate this effect without it loaded?

With that assumption, this effect is entirely down to redefining the method, even with the exact same code (`cell_polys` both times). I think that warrants an edit to the title and the original post to omit the spurious factors of Revise and a name change. I’d also try the `@benchmark` twice before the `@eval`, in case there are any BenchmarkTools first-run shenanigans (very doubtful).

---

<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 10, 2025, 5:34pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/8 "2025-09-10T17:34:34Z")

</div>

> [@Benny](#):
>
> Am I right to assume you didn’t load Revise via startup.jl? If you had, can you replicate this effect without it loaded?

Correct.

> [@Benny](#):
>
> I’d also try the `@benchmark` twice before the `@eval`, in case there are any BenchmarkTools first-run shenanigans (very doubtful).

You are correct. Fresh Julia session, no Revise:

```julia-auto
julia> @benchmark Euler2D.is_cell_contained_by($(sim1.cells[1][1]), $test_poly1)
BenchmarkTools.Trial: 10000 samples with 719 evaluations per sample.
 Range (min … max): 175.549 ns … 56.964 μs ┊ GC (min … max): 0.00% … 99.38%
 Time (median): 193.399 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 260.331 ns ± 669.629 ns ┊ GC (mean ± σ): 11.42% ± 7.87%

  ▃▅▆█▇▅▃▁ ▂▄▃▃▂▂▃▃▄▃▃▂▂▁ ▂
  █████████▇▇▇▆▆▆▅▆▆▆▆▅▄▅▅▄▅▄▆▅▅███████████████▆▅▅▅▃▅▄▄▄▆▄▁▅▃▅▄ █
  176 ns Histogram: log(frequency) by time 453 ns <

 Memory estimate: 464 bytes, allocs estimate: 5.

julia> @benchmark Euler2D.is_cell_contained_by($(sim1.cells[1][1]), $test_poly1)
BenchmarkTools.Trial: 10000 samples with 714 evaluations per sample.
 Range (min … max): 176.485 ns … 58.552 μs ┊ GC (min … max): 0.00% … 99.33%
 Time (median): 197.097 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 289.968 ns ± 864.271 ns ┊ GC (mean ± σ): 12.22% ± 7.10%

     ▅█                                                          
  ▂▄▄██▇▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▂▂▃▃▃▄▄▄▄▄▃▂▂▁▁▁▁▁▁▁▁▁▁ ▂
  176 ns Histogram: frequency by time 408 ns <

 Memory estimate: 464 bytes, allocs estimate: 5.

julia> @eval Euler2D function is_cell_contained_by(cell1, poly)
           cell_polys = cell_boundary_polygon(cell1)
           return all(edge_starts(cell_polys)) do pt
               return PlanePolygons.point_inside_strict(poly, pt)
           end
       end
is_cell_contained_by (generic function with 2 methods)

julia> @benchmark Euler2D.is_cell_contained_by($(sim1.cells[1][1]), $test_poly1)
BenchmarkTools.Trial: 10000 samples with 989 evaluations per sample.
 Range (min … max): 47.076 ns … 467.765 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 50.297 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 50.826 ns ± 8.059 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

                     ▄▆▆▇▇██▆▄▃▂▂▃▃▄▄▄▄▃▂▃▂▁ ▁▁▂▂▁ ▁▁ ▃
  ▆▆▇▅▆▇▇▇██▇▃▁▁▁▁▁▃▆████████████████████████████████▇▇▇██████ █
  47.1 ns Histogram: log(frequency) by time 54.8 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

I do not think I can change the title of the topic, though.

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [September 10, 2025, 6:04pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/9 "2025-09-10T18:04:02Z")

</div>

I’ve changed the thread title, let me know in case you had some other title in mind.

Is the name change a required part of this behaviour btw? i.e. does this happen only when you change the name of the variable, not if you eval the same code (without name change) again?

---

<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 10, 2025, 6:07pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/10 "2025-09-10T18:07:53Z")

</div>

The name change is not required, no. The `@eval`-d function is identical to the function in the source code of the module.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [September 10, 2025, 6:14pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/11 "2025-09-10T18:14:05Z")

</div>

I believe I’ve seen this before. I thought there was a GitHub issue for it but it’s obscure and I can’t find it now. Maybe there isn’t. I thought it was something to do with inlining decisions, `max_methods`, and/or some other arcane internals.

_EDIT: [problem with the unreliable approximation of `Core.Compiler.return_type` · Issue #35800 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/35800) seems to have links to a number of similar issues. It may be related._

---

<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 10, 2025, 6:45pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/12 "2025-09-10T18:45:16Z")

</div>

> [@afleming](#):
>
> I do not think I can change the title of the topic, though.

Probably a participation permissions thing, which is a bit backwards imo. I edited the edit to fit the current findings.

> [@mikmoore](#):
>
> : [unreliable approximation of `Core.Compiler.return_type`](https://github.com/JuliaLang/julia/issues/35800)

Could try `@code_warntype`, JET.jl, or Cthulhu.jl to check if redefinition changes type inference, though the caveat is those redo type inference instead of showing how the compiler actually did it, and at least `@code_warntype` is known to overspecialize for special-cased inputs in some circumstances (`Function`, `Type`, `Vararg`).

---

<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 10, 2025, 7:43pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/13 "2025-09-10T19:43:57Z")

</div>

> [@mikmoore](#):
>
> EDIT: [problem with the unreliable approximation of `Core.Compiler.return_type` · Issue #35800 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/35800) seems to have links to a number of similar issues. It may be related.

In particular:

- [Mysterious inference failure that can be solved by redefining function · Issue #35537 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/35537)

- [Typeinference depends on execution order but should not · Issue #45388 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/45388)

The title of the former issue seems especially relevant to this post. However all three of those issues perhaps have the same underlying cause (deep in the design of the compiler and the language), which may or may not be addressable. That is, the inference is stateful.

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [September 10, 2025, 8:11pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/14 "2025-09-10T20:11:59Z")

</div>

I’m a bit surprised that you’re seeing this when the method you’re calling is the non-reentrant one. I’ve seen this many times, but thought it only happened when a runtime call triggers compilation of the “outer” method before anything has triggered compilation of the “inner” method of a reentrant method definition like the second one. So I’m wondering:

- Is there a call to `is_cell_contained_by` somewhere inside the call graph of the first method? For example, inside `cell_boundary_polygon` or `edge_starts`?
- Does the problem go away if you never define the second method?

---

<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 11, 2025, 9:14am UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/15 "2025-09-11T09:14:27Z")

</div>

> [@danielwe](#):
>
> - Is there a call to `is_cell_contained_by` somewhere inside the call graph of the first method? For example, inside `cell_boundary_polygon` or `edge_starts`?
> - Does the problem go away if you never define the second method?

- There is not a call to `is_cell_contained_by` in the call graph of the first method.
- The problem does not go away if I leave the second method undefined.

`@code_warntype` output:

> **Before redefining the method**
>
> ```julia-auto
> julia> @code_warntype Euler2D.is_cell_contained_by((sim1.cells[1][1]), test_poly1)                                                                                     
> MethodInstance for Euler2D.is_cell_contained_by(::TangentQuadCell{Float64, 3, 12}, ::SClosedPolygon{4, Float64})                                                       
> from is_cell_contained_by(cell1, poly) @ Euler2D ~/projects/stce/shockad/Euler2D.jl/src/cell_simulations/cells.jl:42                                                 
> Arguments                                                                                                                                                              
> #self#::Core.Const(Euler2D.is_cell_contained_by)                                                                                                                     
> cell1::TangentQuadCell{Float64, 3, 12}                                                                                                                               
> poly::SClosedPolygon{4, Float64}                                                                                                                                     
> Locals                                                                                                                                                                 
> #81::Euler2D.var"#81#82"{SClosedPolygon{4, Float64}}                                                                                                                 
> cell_polys::SClosedPolygon{4, Float64}                                                                                                                               
> Body::Bool                                                                                                                                                             
> 1 ─ %1 = Euler2D.cell_boundary_polygon::Core.Const(Euler2D.cell_boundary_polygon)                                                                                     
> │ (cell_polys = (%1)(cell1))                                                                                                                                   
> │ %3 = Euler2D.all::Core.Const(all)                                                                                                                                 
> │ %4 = Euler2D.:(var"#81#82")::Core.Const(Euler2D.var"#81#82")                                                                                                      
> │ %5 = Core.typeof(poly)::Core.Const(SClosedPolygon{4, Float64})                                                                                                    
> │ %6 = Core.apply_type(%4, %5)::Core.Const(Euler2D.var"#81#82"{SClosedPolygon{4, Float64}})                                                                         
> │ (#81 = %new(%6, poly))                                                                                                                                       
> │ %8 = #81::Euler2D.var"#81#82"{SClosedPolygon{4, Float64}}                                                                                                         
> │ %9 = Euler2D.edge_starts::Core.Const(PlanePolygons.edge_starts)                                                                                                   
> │ %10 = cell_polys::SClosedPolygon{4, Float64}                                                                                                                       
> │ %11 = (%9)(%10)::SVector{4, SVector{2, Float64}}                                                                                                                   
> │ %12 = (%3)(%8, %11)::Bool                                                                                                                                          
> └── return %12
> 
> ```

> **After redefining the method**
>
> ```julia-auto
> julia> @code_warntype Euler2D.is_cell_contained_by((sim1.cells[1][1]), test_poly1)
> MethodInstance for Euler2D.is_cell_contained_by(::TangentQuadCell{Float64, 3, 12}, ::SClosedPolygon{4, Float64})
> from is_cell_contained_by(cell1, poly) @ Euler2D REPL[4]:1
> Arguments
> #self#::Core.Const(Euler2D.is_cell_contained_by)
> cell1::TangentQuadCell{Float64, 3, 12}
> poly::SClosedPolygon{4, Float64}
> Locals
> #244::Euler2D.var"#244#245"{SClosedPolygon{4, Float64}}
> cell_polys::SClosedPolygon{4, Float64}
> Body::Bool
> 1 ─ (cell_polys = Euler2D.cell_boundary_polygon(cell1))
> │ %2 = Euler2D.all::Core.Const(all)
> │ %3 = Euler2D.:(var"#244#245")::Core.Const(Euler2D.var"#244#245")
> │ %4 = Core.typeof(poly)::Core.Const(SClosedPolygon{4, Float64})
> │ %5 = Core.apply_type(%3, %4)::Core.Const(Euler2D.var"#244#245"{SClosedPolygon{4, Float64}})
> │ (#244 = %new(%5, poly))
> │ %7 = #244::Euler2D.var"#244#245"{SClosedPolygon{4, Float64}}
> │ %8 = cell_polys::SClosedPolygon{4, Float64}
> │ %9 = Euler2D.edge_starts(%8)::SVector{4, SVector{2, Float64}}
> │ %10 = (%2)(%7, %9)::Bool
> └── return %10
> 
> ```

`@inferred` succeeds in both cases.

---

<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 11, 2025, 10:05am UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/16 "2025-09-11T10:05:52Z")

</div>

The `@code_warntype` reports do differ, but the program and inferred types don’t seem to. I don’t know if there’s a deeper significance, but it just seems like an arbitrary decision to opt out of explicitly identifying some callee functions as `Const` and binding them to temporary names. That doesn’t imply the compiler actually stops knowing they are `const` after redefinition; otherwise we’d expect to _lose_ performance. Wonder if `@code_llvm` can catch something?

Just for a sanity check, have you also cached the results (maybe from a single run) and compared them before and after the redefinition, if that’s even possible? Should also make sure that both versions are giving the correct results.

> [@nsajko](#):
>
> the inference is stateful.

The interesting part of this is the examples in #35800 show a type inference discrepancy before and after compilation+execution, but this example’s optimization change is strictly observed in execution before and after redefinition and isn’t yet shown to be caused by type inference changes. Could try some `Base.return_types` or `@code_warntype` reports before the benchmarks as well?

The examples in #35800 also appeared to stop reproducing after v1.8; [this example](https://github.com/JuliaLang/julia/issues/35800#issuecomment-1097605769) doesn’t reproduce in v1.11.6 because `Base.return_types` populates `mi.cache`. So while there may be a shared underlying cause, it’s at least somewhat different and could result in a new MWE for the issue.

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [September 11, 2025, 2:49pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/17 "2025-09-11T14:49:01Z")

</div>

> [@Benny](#):
>
> The examples in #35800 also appeared to stop reproducing after v1.8

Interesting, I didn’t realize that. But this kind of stateful behavior is still encountered from time to time, see for example [Type instability in nested quadgk calls](https://discourse.julialang.org/t/type-instability-in-nested-quadgk-calls/126667)

---

<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 11, 2025, 7:55pm UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/18 "2025-09-11T19:55:14Z")

</div>

At least this [linked MWE](https://github.com/JuliaLang/julia/issues/49970) still works on v1.11.6 (you can just redefine both methods before uncommenting the call in the same session to improve `@code_warntype`). However, I added `@benchmark` reports to that, and the improved type inference doesn’t improve runtime performance (median 2.3us, 44 allocations of 2.55 KiB) for that example; it’s not clear to me which `@code_warntype` report reflects the actual compiled code. Whether that’s down to differences in the program or this particular redefinition optimization phenomenon being fundamentally different, I don’t know. Part of the problem is we don’t really have a standard protocol for discovering compiler statefulness.

---

<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, 5:39am UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/19 "2025-09-12T05:39:34Z")

</div>

This is the code on Github:

> <https://github.com/STCE-at-RWTH/Euler2D.jl/blob/c273f9b2f3a6d4c6c551888698d6685c4ca10910/src/cell_simulations/cells.jl#L42-L47>

> [@afleming](#):
>
> ```julia-repl
> julia> @benchmark Euler2D.is_cell_contained_by($test_cell, $test_poly)
> 
> ```

I want to look into this issue, can you provide a reproducer? In particular, how to define `test_cell` and `test_poly`?

---

<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 12, 2025, 11:52am UTC](https://discourse.julialang.org/t/identical-method-redefinition-suspiciously-optimizes-runtime-and-allocations/132156/20 "2025-09-12T11:52:46Z")

</div>

> [@nsajko](#):
>
> I want to look into this issue, can you provide a reproducer? In particular, how to define `test_cell` and `test_poly`?

Indeed I can. I’ve stripped all of the irrelevant bits out of the two packages (Euler2D and PlanePolygons) and put them together into a MWE. The behavior can still be reproduced, and the MWE only depends on StaticArrays.jl.

[MWE here.](https://gist.github.com/aj-fleming/7e5ae49126339e79b2154b1a31b9423d)

> **Reproduction using the MWE**
>
> ```julia-auto
> julia> include("mwe.jl")
> Main.Euler2D_MWE
> 
> julia> using StaticArrays, .PlanePolygons_MWE, .Euler2D_MWE, BenchmarkTools
> 
> julia> test_cell = TangentQuadCell_MWE(1, SVector(1.0, 4.0, 0.0, 9.87), SMatrix{4,3}(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0), SVector(-1.49687, 0.03125), SVector(0.00625, 0.00625))
> TangentQuadCell_MWE{Float64, 3, 12}(1, [1.0, 4.0, 0.0, 9.87], [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0; 0.0 0.0 0.0], [-1.49687, 0.03125], [0.00625, 0.00625])
> 
> julia> test_poly1 = SClosedPolygon(@SVector([SVector(-1.3, 1.5), SVector(-1.4, 1.5), SVector(-1.4, 1.75), SVector(-1.3, 1.75)]))
> SClosedPolygon{4, Float64}(SVector{2, Float64}[[-1.3, 1.5], [-1.4, 1.5], [-1.4, 1.75], [-1.3, 1.75]])
> 
> julia> @benchmark Euler2D_MWE.is_cell_contained_by($test_cell, $test_poly1)
> BenchmarkTools.Trial: 10000 samples with 709 evaluations per sample.
> Range (min … max): 190.546 ns … 2.343 μs ┊ GC (min … max): 0.00% … 87.98%
> Time (median): 194.135 ns ┊ GC (median): 0.00%
> Time (mean ± σ): 204.842 ns ± 48.312 ns ┊ GC (mean ± σ): 4.06% ± 9.49%
> 
> ▇█▄▅▄▁ ▁▁▁▁▁ ▂
> ███████▇▆▆▅▄▆▁▃▃▁▃▁▃▁▁▃▁▁▁▁▁▃▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▆████████ █
> 191 ns Histogram: log(frequency) by time 366 ns <
> 
> Memory estimate: 544 bytes, allocs estimate: 6.
> 
> julia> @eval Euler2D_MWE function is_cell_contained_by(cell1, poly)
> cell_poly = cell_boundary_polygon(cell1)
> return all(edge_starts(cell_poly)) do pt
> return PlanePolygons_MWE.point_inside_strict(poly, pt)
> end
> end
> is_cell_contained_by (generic function with 1 method)
> 
> julia> @benchmark Euler2D_MWE.is_cell_contained_by($test_cell, $test_poly1)
> BenchmarkTools.Trial: 10000 samples with 989 evaluations per sample.
> Range (min … max): 47.239 ns … 101.062 ns ┊ GC (min … max): 0.00% … 0.00%
> Time (median): 50.814 ns ┊ GC (median): 0.00%
> Time (mean ± σ): 51.116 ns ± 1.927 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
> 
> ▃▄▅▇██▆▃▁ ▁▂▂▁▁▁▁ ▂
> ▇█▄▁▃▅▇▄▁▅▇▃▁▄██████████▆▅▄▄▄▃▃▄▅▆██████████▇▆▆▄▃▃▃▃▁▄▃▃▃▄▅▅ █
> 47.2 ns Histogram: log(frequency) by time 58 ns <
> 
> Memory estimate: 0 bytes, allocs estimate: 0.
> 
> ```

I am using Julia 1.11.6 (2025-07-09).

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