I stumbled across a case of bad practice that resulted in an error, but I am not sure why.
function g(y)
function f(x)
f = x * y
return f
end
f(y)
f(y)
end
g(0.2)
I really should not define a variable f within a function f. The about code throws ERROR: LoadError: MethodError: objects of type Float64 are not callable and points to the second call of f within g.
At that time, f is a Float64 but why? Does that have to do with inlining? Calling f once instead of twice within g works out fine.
julia> f = 1.0
1.0
julia> x = 2.0
2.0
julia> f(x)
ERROR: MethodError: objects of type Float64 are not callable
when you do f(y), f becomes the result of f = x*y which happens to be a Float64. And you are then trying to “call” that float with parameter y.
julia> function g(y)
function f(x)
f = x * y
return f
end
println(f," ",typeof(f))
f(y)
println(f," ",typeof(f))
f(y)
end
g (generic function with 1 method)
julia> g(2)
f var"#f#5"{Int64}
4 Int64
This has nothing to do with inlining and is entirely due to how local scope works. Function g introduces a local scope. It has a local variable f, which is initially bound to a function. Now inside that function, you also assign to f. Because this is all inside a local scope, that inner f assignment doesn’t shadow the outer f function (like it would if this inner function were defined at global scope) and instead it is the same binding. Thus a side-effect of executing that inner function is changing what f refers to.