Avoid method dispatch at runtime
Author jlapeyre
20 Stars
Updated Last
1 Year Ago
Started In
September 2020


Provides the macro @unionsplit to dispatch "manually" on types rather than rely on runtime multiple dispatch.

If type information is hidden from the compiler, then the dispatch system has to select the correct method at runtime, which can be very slow. In this case it can be much faster to use conditional statements to check the type. Inside each branch of the conditional, the type is known and the call can be devirtualized or inlined.

This macro is based on ideas of Tim Holy and Takafumi Arakaki.


In the following examples, using @union_split is much faster than relying on multiple dispatch, which must happen at runtime.

using BenchmarkTools
using ManualDispatch

func(x::Int) = 1
func(x::Float64) = 1

# The type of the arrays is `Vector{Any}`, so that the compiler cannot choose the
# required method for `func` at compile time.
const x_int = Any[1 for i in 1:1000]
const x_float = Any[1.0 for i in 1:1000]
const x_mixed = Any[iseven(i) ? 1 : 1.0 for i in 1:1000]

function ex_union_split(x)
    for y in x
        @unionsplit((Int, Float64), func(y))

function ex_runtime_dispatch(x)
    for y in x

print("Manual union split with array of Int")
@btime ex_union_split(x_int)

print("Runtime dispatch with array of Int")
@btime ex_runtime_dispatch(x_int)

print("Manual union split with array of Float64")
@btime ex_union_split(x_float)

print("Runtime dispatch with array of Float64")
@btime ex_runtime_dispatch(x_float)

print("Manual union split with mixed array")
@btime ex_union_split(x_mixed)

print("Runtime dispatch with mixed array")
@btime ex_runtime_dispatch(x_mixed)