I wonder is it a good idea to allocate temporary arrays in let-block, which wraps some function? Some toy example: instead of
function foo(x)
y = zeros(100)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
I will write something like:
let
const y = zeros(100) # otherwise foo will be type-unstable due to 'global' y
function foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
end
It can be easily checked via @benchmark macro that in the second case memory for y-array will be allocated only once, which significantly improves performance (in my not-toy case). I'm wondering is it a "julian-way" to do such things?
I will give you an answer for Julia 1.0. For earlier versions of Julia the situation would be a bit different.
Point 1. Your code with let
will not run under Julia 1.0 as let
creates local scope and in local scope you are not allowed to use const
.
Point 2. It is fully OK to do something like this in global scope:
const y = zeros(100) # otherwise foo will be type-unstable due to 'global' y
function foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
and you will have good performance as Julia 1.0 knows that y
has constant type and will optimize it. The consequence is that you will have y
in global scope and foo
in methods table (i.e. you can call foo
using its name).
Point 3. You can also use let
block like this:
const foo = let y = zeros(100)
function inner_foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
end
This time y
is defined only in local scope and does not leak out to global scope. Also inner_foo
is not defined in global scope therefore you have to assign the return value of let block to a variable foo
that then can be used to make calls (I make it a const
to improve performance if it gets used in some functions later on)
Point 4. Note, however, that this almost identical code will not be as good, as Julia 1.0 has problems with type inference of variable y
(hopefully this will be fixed in the future)
const foo = let
y = zeros(100)
function inner_foo(x)
for i in 1 : 100
y[i] = 2*x[i] - 1
end
do_something(y)
end
end
In summary: the decision if you use let
block depends mostly on what you have to be visible in global
scope (as what is defined in let
is not visible in global scope) and if you use let
block it is best to define variables you want to use as a part of let
block definition.