Understanding allocations when collapsing function arugments

Yes, this is a tricky thing. I guess you mean something like:

julia> function main(x)
         g(x,z) = x + z
         f(x) = g(x,y)
         y = 2
         f(x)
       end
main (generic function with 1 method)

julia> @btime main(1)
  20.894 ns (1 allocation: 16 bytes)
3

This is confusing and there are other discussion whether that should raise an error, a warning, or something else. The problem is that there is an ambiguity on whether y is a constant in the local scope, if it can vary, and that apparently is making the compiler make bad choices (outside my scope of understanding).

The safe alternative is being more explicit on what one wants:

julia> function main(x)
         g(x,y) = x + y
         f(x,inner_g) = inner_g(x)
         y = 2
         f(x, x -> g(x,y))
       end
main (generic function with 1 method)

julia> @btime main(1)
  0.025 ns (0 allocations: 0 bytes)
3

But with a lot of different parameters, I would play even safer and use a struct:

julia> struct Params
         y::Int
       end
       function main(x)
         g(x,y) = x + y 
         f(x,p) = g(x,p.y)
         p = Params(2)
         f(x,p)
       end
main (generic function with 1 method)

julia> @btime main(1)
  0.023 ns (0 allocations: 0 bytes)
3


I just opened another thread with a related issue: Performance closures with changing value of closed over variables

1 Like