# Avoid runtime dispatch when overloading \`isless()\`

**URL:** <https://discourse.julialang.org/t/avoid-runtime-dispatch-when-overloading-isless/78366>\
**Category:** Performance\
**Created:** [March 24, 2022, 12:35am UTC](https://discourse.julialang.org/t/avoid-runtime-dispatch-when-overloading-isless/78366 "2022-03-24T00:35:31Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![maxkapur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maxkapur/32/21208_2.png) [@maxkapur](https://discourse.julialang.org/u/maxkapur)\
**Post date:** [March 24, 2022, 12:35am UTC](https://discourse.julialang.org/t/avoid-runtime-dispatch-when-overloading-isless/78366/1 "2022-03-24T00:35:31Z")

</div>

I have been learning to use JET.jl to improve the performance of my code. I am still getting familiar with its output. I would appreciate some help understanding why the function below produces a runtime dispatch warning in `@report_opt`.

Basically, what we do is define a struct `Rectangle`, overload `isless()` to sort rectangles by their area, then create a function that generates `m` random rectangles and finds the largest one and its index.

```julia
julia> import Base.isless

julia> using JET

julia> struct Rectangle
           width::Float64
           height::Float64
       end

julia> isless(r1::Rectangle, r2::Rectangle) = isless(r1.width * r1.height, r2.width * r2.height)
isless (generic function with 44 methods)

julia> function largestrandomrectangle(m::Int)
           rects = Rectangle[Rectangle(rand(), rand()) for _ in 1:m]
           
           findmax(rects)
       end
largestrandomrectangle (generic function with 1 method)

julia> @report_opt largestrandomrectangle(100)
═════ 2 possible errors found ═════
┌ @ REPL[5]:2 Main.rand()
│┌ @ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.8/Random/src/Random.jl:257 #self#(Random.default_rng(), Random.Float64)
││┌ @ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.8/Random/src/Random.jl:257 Random.Val(1)
│││┌ @ essentials.jl:714 %1()
││││ runtime dispatch detected: %1::Type{Val{_A}} where _A()
│││└─────────────────────
┌ @ REPL[5]:4 Main.findmax(rects)
│┌ @ reducedim.jl:1159 Base.#findmax#821(Base.:, #self#, A)
││┌ @ reducedim.jl:1159 Base._findmax(A, dims)
│││┌ @ reduce.jl:911 Base.findmax(Base.identity, a)
││││┌ @ reduce.jl:885 Base.mapfoldl(#275, Base._rf_findmax, Base.pairs(domain))
│││││┌ @ reduce.jl:162 Base.#mapfoldl#257(Base._InitialValue(), #self#, f, op, itr)
││││││┌ @ reduce.jl:162 Base.mapfoldl_impl(f, op, init, itr)
│││││││┌ @ reduce.jl:44 Base.foldl_impl(op′, nt, itr′)
││││││││┌ @ reduce.jl:49 Base.reduce_empty_iter(op, itr)
│││││││││┌ @ reduce.jl:370 Base.reduce_empty_iter(op, itr, Base.IteratorEltype(itr))
││││││││││┌ @ reduce.jl:371 Base.reduce_empty(op, Base.eltype(itr))
│││││││││││┌ @ reduce.jl:348 Base.mapreduce_empty(#275, $(QuoteNode(Base.BottomRF{typeof(Base._rf_findmax)}(Base._rf_findmax))), _)
││││││││││││ runtime dispatch detected: Base.mapreduce_empty(#275, $(QuoteNode(Base.BottomRF{typeof(Base._rf_findmax)}(Base._rf_findmax)))::Base.BottomRF{typeof(Base._rf_findmax)}, _::Type{Pair{Int64, Rectangle}})
│││││││││││└─────────────────

```

The first issue shows up even if you call `@report_opt rand()`, so I am not sure I can do anything about it.

The second issue is what confuses me. I _think_ what it is saying is that my function will error if the `rects` is empty (i.e. if `m=0`). But that is exactly what I want to happen!

```julia
julia> findmax(Rectangle[])
ERROR: MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer

```

Am I safe to ignore the warning, or will I actually obtain better performance by modifying `largestrandomrectangle()` to return some kind of dummy object for empty input?

---

<div class="post-metadata">

**Author:** ![lawless-m](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lawless-m/32/30869_2.png) [@lawless-m](https://discourse.julialang.org/u/lawless-m)\
**Post date:** [March 24, 2022, 7:01am UTC](https://discourse.julialang.org/t/avoid-runtime-dispatch-when-overloading-isless/78366/2 "2022-03-24T07:01:09Z")

</div>

Looking at the [source code of findmax](https://github.com/JuliaLang/julia/blob/bf534986350a991e4a1b29126de0342ffd76205e/base/reduce.jl#L806-L829)

it does this

```julia
findmax(itr) = _findmax(itr, :)
_findmax(a, ::Colon) = findmax(identity, a)

```

and [the documentation for the call using `identity`](https://docs.julialang.org/en/v1/base/collections/#Base.findmax) says

> `domain` must be a non-empty iterable.

So I guess the documentation for `findmax(itr)` should also mention this condition.

It is the caller’s responsibility to check for valid arguments, so how you handle that is up to you.

The maximum area of no rectangles is …

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [March 24, 2022, 8:22am UTC](https://discourse.julialang.org/t/avoid-runtime-dispatch-when-overloading-isless/78366/3 "2022-03-24T08:22:28Z")

</div>

_off topic_

> [@lawless-m](#):
>
> The maximum area of no rectangles is …

the minimum area of no rectangles
