The second statement, print (y) will work ok. It just prints nil.
It's important to realise that Lua does not "look ahead" and initialise global variables before it processes a file. Global variables are available anywhere but are not auto-initialised in any way. For instance
x=y
y=2print(x,y)
prints "nil,2".
The other thing to notice is that functions are first class values in Lua, they are not special like in other languages. The statement
function foo(a)print(a)end
is equivalent to
foo=function(a)print(a)end
which makes it clearer that function assignment is the same as variable assignment. Setting foo=function (a)... is the same as setting foo=5. So this code will give an error.
Although foo is a global variable, the foo assignment has not been done when we call foo, so foo has value nil and it is illegal to call such a value. Of course, all is well if rearrange
x,y,foo,bar=nil,nil,nil,nilfunction foo(a)print(bar(a+1))endfunction bar(a)return a*2end
x=y
y=2print(x,y,foo(2))-- prints 6, nil, 2
Note I've set x,y,foo and bar to nil at the beginning. There's no need to do this but I find it helps me remember what globals I've got. Foo and bar are declared before they are called so that's fine. But notice that when the interpreter is initialising foo, bar is referred before we have set it up. That's fine: it's only when a function is called that it needs to be non-nil. However, if you make bar local this wont work.
function foo(a)print(bar(a+1))--Error attempt to call global 'bar' (a nil value)endlocalfunction bar(a)return a*2end
x=y
y=2print(x,y,foo(2))
function x()
y =3function z()
u =5print(u)endlocal a =3localfunction b()
c =5print(c)endend
x()
z()-- output: 5print(u,y,c,a)-- output: 5 3 nil nil
Because we actually call x(), globals z(), u and y are set up. a is local so is destroyed when x() returns. c is global but is never set since b() is never called.
function foo(a)print(bar(a+1))--Error attempt to call global 'bar' (a nil value)endlocalfunction bar(a)return a*2end
x=y
y=2print(x,y,foo(2))
I'm not sure why!
I'll take a stab at this.
If you put the local function bar() before the function foo() it'll work - this is "I think" because when the parser pre-compiles foo it can't find bar (it's not been defined yet) and so assumes it's a global bar it's looking for.
So the fact that you then have a local bar is irrelevant as foo's already looking for the global one.
If you declare bar first (either global or local) then foo will know that bar exists within the current scope and thus generate the correct code.
At least that's my (current) understanding.
WhiteTree Games - Home, home on the web, where the bits and bytes they do play! #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
Actually the error does not occur until the line print(x,y,foo(2)) is reached. There is no error when function foo is precompiled as you can see if you delete the line print (x,y,foo(2)), then the program will run without error.
Lua has no problem compiling functions which call other functions which are currently nil. It's only when a function is actually called that it needs to be defined.
The reason foo cannot access bar when its called is because functions only have access to three things: 1) Their arguments 2) global variables 3) Their upvalues
Upvalues, or "external local variables" are local variables outside the scope of the function and defined before the function. The example can be fixed if we add the line local bar
local bar
function foo(a)print(bar(a+1))endfunction bar(a)return a*2end
x=y
y=2print(x,y,foo(2))
now foo has an upvalue bar which is initially nil but will be set before we call foo.
Upvalues and closures are among the most complex features of Lua. Personally I just declare all functions as global to avoid this sort of problem.
Actually the error does not occur until the line print(x,y,foo(2)) is reached. There is no error when function foo is precompiled as you can see if you delete the line print (x,y,foo(2)), then the program will run without error.
Exactly it's not until the code is run that Lua realises that it's actually attempting to call the global bar (which is nil), adding the local bar, is a bit like making a prototype of a function (or declaring a variable as "extern") in C and is something I use a lot when dealing with event handlers.
Upvalues and closures are among the most complex features of Lua. Personally I just declare all functions as global to avoid this sort of problem.
Agreed although you can do some seriously powerful things with them - personally, I just keep everything in a module local and declare all the locals first.
WhiteTree Games - Home, home on the web, where the bits and bytes they do play! #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
I often use forward declaration when I need to keep (for myself) instructions in the sequence order that feels right. It also helps me to avoid creating too many global variables/functions.
Comments
Likes: atilim
It's important to realise that Lua does not "look ahead" and initialise global variables before it processes a file. Global variables are available anywhere but are not auto-initialised in any way. For instance
The other thing to notice is that functions are first class values in Lua, they are not special like in other languages. The statement
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975
If you put the local function bar() before the function foo() it'll work - this is "I think" because when the parser pre-compiles foo it can't find bar (it's not been defined yet) and so assumes it's a global bar it's looking for.
So the fact that you then have a local bar is irrelevant as foo's already looking for the global one.
If you declare bar first (either global or local) then foo will know that bar exists within the current scope and thus generate the correct code.
At least that's my (current) understanding.
#MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
Lua has no problem compiling functions which call other functions which are currently nil. It's only when a function is actually called that it needs to be defined.
The reason foo cannot access bar when its called is because functions only have access to three things:
1) Their arguments
2) global variables
3) Their upvalues
Upvalues, or "external local variables" are local variables outside the scope of the function and defined before the function. The example can be fixed if we add the line local bar
Upvalues and closures are among the most complex features of Lua. Personally I just declare all functions as global to avoid this sort of problem.
https://github.com/gideros/gideros
https://www.youtube.com/c/JohnBlackburn1975
#MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
It also helps me to avoid creating too many global variables/functions.
Edit : same as you said, @techdojo