function main()
function sub()
fun(f) = f
return x -> fun(x)
end
fun = sub()
fun(1)
end
A call to main()
results in a stack overflow. If sub()
returned fun
instead of x -> fun(x)
or the assignment in main()
was fun2 = sub()
or calling sub()(1)
all would be OK.
Is this construct against Julia’s grammar?
No, it is parsed fine and I think it is executed correctly.
What happens is that sub
takes fun
from the scope of main
, which you happen to overwrite, so it ends up being recursive.
Interesting that this happens even if fun
is first assigned/defined after the local function assignment/definition. I would assume that any binding I assign a value inside a local function which does not exist yet in the outer scope will end up being local to the local function, not that it “retroactively” makes the binding in the local function to refer to the binding in the outer scope.
This just happen if fun
is assigned in the outer scope? It works as I expect if I just try to print the binding in the outer scope.
function main()
function sub()
fun(f) = f
return x -> fun(x)
end
show(fun)
sub()
end
main()
In other words, this says fun
is not defined. Counter-intuitive for me that defining a binding at any point of the scope makes it available before it was defined in some cases (i.e., to be captured by a local function) but not change the answer of @isdefined
.
function main()
function sub()
fun(f) = f
return x -> fun(x)
end
println(@isdefined(fun))
fun = sub()
fun(1)
end
This outputs false
before the stack overflow.
1 Like
This is the documented behavior: right in the beginning of the relevant chapter, you will find that
The scope of a variable cannot be an arbitrary set of source lines; instead, it will always line up with one of these blocks.
This is later elaborated with examples.
This is actually a very clean way of thinking about scope: relying on the order of things happening can get chaotic pretty quickly (think of branches, etc).
I think it is best to avoid writing code like this, it can become very hard to reason about.
1 Like
As pointed out by @Tamas_Papp, the docs are explicit about nested functions and their parent’s scope:
Note that nested functions can modify their parent scope’s local variables:
1 Like