Let’s say I have some parametric struct struct Foo{T} ... end
, and I prepare a vector of Foos.
I now have a loop that for a given vector, which doesn’t mutate during the loop, picks a random index in the loop, and executes an algorithm, which varies based on the type T
.
I want to avoid dynamic dispatch in this case, since the structure of the vector is known beforehand. I.e. if I pick index n
randomly, at the beginning of the loop it is already known which algorithm should run. Just doing this naively will result in non-specified code which is slow.
One (hacky?) way of solving this is with generated functions and a function barrier.
I can create a tuple type from the vector of food and essentially a switch statement, hardcoding the specific algorithm to be used for every index.
# Algo for Foo{Int64}
function fooalgo(f::Foo, ::Type{Int64})
...
end
# Algo for Foo{...}
function fooalgo(f::Foo, Type{...})
....
end
....
@generated function generated_loop(foos::Vector{Foo}, somerange, tt::Type{Tuple})
# using the type tt, params = tt.parameters
# generate the following code:
# for i in somerange
# idx = rand(1:length(params))
# if idx == 1
# fooalgo(foos[1], params[1])
# elseif ...
# ...
# elseif idx == length(params)
# fooalgo(foos[end], params[end])
# end
end
function loop(foos, somerange)
tt = Tuple{[typeof(foo).parameters[1] for foo in foos]...}
generated_loop(foos, somerange, tt)
end
This is the only way I could think up of. Is this a reasonable way of doing things, or is there a better way? Also, would this in practice be faster? I would think the if else statement would be faster to compute that the dynamic dispatch.