Take this MWE function which simply returns the argument at the specified index idx
or y
in the vector v
:
function foo(v::Vector{Int}, idx::Union{Nothing,Int}=nothing; y::Union{Nothing,Integer}=nothing)
if !xor(isnothing(idx), isnothing(y))
error("invalid arguments")
end
if isnothing(y)
return v[idx]
else
return v[y]
end
end
With Benchmark tools we see:
julia> a = [1,2,3,4,5,6,7,8,9,10];
julia> @btime foo($a,1);
1.375 ns (0 allocations: 0 bytes)
julia> @btime foo($a,y=1);
1.333 ns (0 allocations: 0 bytes)
No surprises here, zero allocations. Now let’s make one tiny change and let the keyword argument type be Union{Nothing, <:Integer}
instead of Union{Nothing, Integer}
, so:
function foo2(v::Vector{Int}, idx::Union{Nothing,Int}=nothing; y::Union{Nothing,<:Integer}=nothing)
if !xor(isnothing(idx), isnothing(y))
error("invalid arguments")
end
if isnothing(y)
return v[idx]
else
return v[y]
end
end
Now we see with foo2
:
julia> @btime foo2($a,1);
1.333 ns (0 allocations: 0 bytes)
julia> @btime foo2($a,y=1);
184.793 ns (3 allocations: 96 bytes)
Why would there be allocations by having the <:
in vs not for the keyword argument? I do not see similar behavior when changing the non-keyword argument to <:Integer
?