I have come across some somewhat unexpected behavior when passing types as arguments to a function. For reference, I am using the current Julia 1.10.10 (the current LTS). I am somewhat unclear what causes this behavior, so if anyone has any idea, I would love to know. This seems to have something to do with the JIT compiler, but I don’t know exactly what.
Consider the following minimal example code, which is just allocating a random array of all 0 and 1 values, then flipping the bits in place randomly (to avoid the compiler optimizing away my loop). This test_function_1
does not allocate when called (i.e. the return value, a == 0
).
function flip_bit!(state::Vector{T}, ind) where T
state[ind] = one(T) - state[ind]
end
function test_function_1(n::Integer; num_flips=1000)
state = rand((0, 1), n)
randinds = rand(1:n, num_flips)
a = @allocations for ind in randinds
flip_bit!(state, ind)
end
return a
end
However, if I pass a type as a parameter, and make the initial array as follows in a new function, which I call test_function_2
:
function test_function_2(n::Integer; num_flips=1000, T=Int64)
state = rand((zero(T), one(T)), n)
randinds = rand(1:n, num_flips)
a = @allocations for ind in randinds
flip_bit!(state, ind)
end
return a
end
This function will not allocate when called with T=Int64
, however, if you pass the type as a floating point number, it will allocate (i.e. test_function_2(10, T=Float64)
will allocate for each loop iteration give or take a few allocations for initial compilation). Note that we could also have written state = T.(rand((0, 1), n))
and the behavior would be the same. Also note that this behavior is not caused by the loop, as we could remove flip_bit!
from the loop and it would still allocate once.
This behavior does not occur however if the type is inferred from a parameter passed into the function. Observe this third test function:
function test_function_3(n::Integer; num_flips=1000, dummy::T=0) where T
state = rand((zero(T), one(T)), n)
randinds = rand(1:n, num_flips)
a = @allocations for ind in randinds
flip_bit!(state, ind)
end
return a
end
This function doesn’t allocate when called with dummy=0.0
. Does anyone more enlightened than myself know what is going on here?
Example behavior from the REPL is shown below, where I have defined the functions in a file called example.jl
julia> include("example.jl");
julia> test_function_1(10)
0
julia> test_function_2(10)
26
julia> test_function_2(10)
0
julia> test_function_2(10; T=Int32)
764
julia> test_function_2(10; T=Int32)
0
julia> test_function_2(10; T=Float64)
1764
julia> test_function_2(10; T=Float64)
1000
julia> test_function_3(10)
0
julia> test_function_3(10; dummy=0.0)
0
Any insights would be greatly appreciated, thank you! If this is a duplicate to a previous post, I apologize - I tried to find one and didn’t.