I am puzzled by an error message in VS code. I have the folloing function below and VS Code is telling me that at line 11, where I compute the likelihood, that VARIABLE HAS BEEN ASSIGNED BUT NOT USED.
The function seems to work fine! It is NOT returning 0.0, it is returning the correct value.
function dummyfunc(tile::UInt32, W::Vector{BigFloat})::BigFloat
likelihood = BigFloat(0.0)
T = T3x3(W)
a = pairs(patchdictionary)
foreach(a) do paire
if tile == paire[1]
p1 = Int(paire[1] & 0x000000ff)
p2 = Int((paire[1] & 0x0000ff00) >> 8)
p3 = Int((paire[1] & 0x00ff0000) >> 16)
p4 = Int((paire[1] & 0xff000000) >> 24)
likelihood = (W[p1] * W[p2] * W[p3] * W[p4]) / T # <--- This is where 'likelihood' is greyed out by VS Code
end
end
return likelihood
end
It seem a bug in the linter for me. Yet, isn´t this clearer?
function dummyfunc(tile::UInt32, W::Vector{BigFloat})::BigFloat
likelihood = BigFloat(0.0)
T = T3x3(W)
for paire in pairs(patchdictionary)
if tile == paire[1]
p1 = Int(paire[1] & 0x000000ff)
p2 = Int((paire[1] & 0x0000ff00) >> 8)
p3 = Int((paire[1] & 0x00ff0000) >> 16)
p4 = Int((paire[1] & 0xff000000) >> 24)
likelihood = (W[p1] * W[p2] * W[p3] * W[p4]) / T # <--- This is where 'likelihood' is greyed out by VS Code
end
end
return likelihood
end
help?> foreach
search: foreach
foreach(f, c...) -> Nothing
Call function f on each element of iterable c. For multiple iterable arguments, f is called elementwise, and
iteration stops when any iterator is finished.
foreach should be used instead of map when the results of f are not needed, for example in foreach(println, array).
Therefor it seems to be the right thing to say it’s not used.
Anyways, as we are in a function, the scope of likelihood seems not to change, so the value of likelihood is changed inside of the anonymous function, e.g. a MWE (VSCode shows the same behaviour):
julia> function foo()
a=[1,2,3]
y=0
foreach(a) do x
y=x
end
y
end
foo (generic function with 1 method)
julia> foo()
3
Hard scope: If x is not already a local variable and assignment occurs inside of any hard scope construct (i.e. within a let block, function or macro body, comprehension, or generator), a new local named x is created in the scope of the assignment;
and the result of above MWE seem to contradict this. (Julia 1.9 here)
So, VSCode is right but scope rules seem to be not fulfilled or misinterpreted by me.
I think removing the do syntax always makes things clearer:
julia> function foo()
x = 1
y = [1,2]
foreach(el -> x += 1, y)
return x
end
foo (generic function with 1 method)
julia> foo()
3
the anonymous function el -> x += 1 is closing over the x value. In general it is not a good idea to modify closed over variables, but that what’s going on there. I think it is a linker bug, there.
I think this example is a bit misleading.
It would better be written as:
function foo2()
a=[1,2,3]
y=0
foreach( x-> y=x, a)
y
end
Or even more explicit:
julia> function foo3()
a=[1,2,3]
y=0
function f(x)
y=x
end
f(3)
y
end
foo3 (generic function with 1 method)
julia> foo3()
3
So, the remaining question is:
Why does function f(x) inside foo3 not introduce a new local scope with a local y ?
Instead it inherits the scope of foo3.
Or: Why is local needed here:
julia> function foo4()
a=[1,2,3]
y=0
function f(x)
local y=x
end
f(3)
y
end
foo4 (generic function with 1 method)
julia> foo4()
0
I can’t find a good explanation from the docs of scope.
"When x = <value> occurs in a local scope, Julia applies the following rules to decide what the expression means based on where the assignment expression occurs and what x already refers to at that location:
Existing local: If x is already a local variable, then the existing local x is assigned;"
Inner function scopes are just like any other nested local scope. In particular, if a variable is already a local outside of an inner function and you assign to it in the inner function, the outer local variable is updated.
One more reason to avoid nested functions when possible.
Note one additional danger in this case: I don’t see any guarantee concerning the order of evaluation of foreach, meaning that in principle the result of such a calculation can change, and there could be even data races.