Allocations when moving loop into a function

Hi, and welcome to the Julia community!

The problem is that in

@btime begin
  for i = 1:n
    @views foo!((F[i, :]), (A[i, :]))
  end
end

n is a (non-const, non-typed) global variable, meaning the compiler doesn’t know its type, nor that of i. So in every iteration we need to check the types involved. The same is true for A and F. If you declare them all const (note that this still allows in-place mutation of the Arrays), I get

julia> @btime begin
  for i = 1:n
    @views foo!((F[i, :]), (A[i, :]))
  end
end
  13.000 μs (0 allocations: 0 bytes)

Alternatively, BenchmarkTools.jl also allows for interpolating global variables using $:

julia> ... # non-const n, A, F

julia> @btime begin
           for i = 1:$n
               @views foo!(($F[i, :]), ($A[i, :]))
             end
         end
  11.000 μs (0 allocations: 0 bytes)

I’m not sure why we don’t need such interpolation for bar!, though. But even if we did, we only need to determine the types of F and A once, instead of once in every iteration, so the timing and allocation difference between the interpolated and non-interplated version would be much less pronounced.