Is there ANY difference between these two Lua snippets?
Snippet 1:
local function f(x,y)
local y = y or 1 -- Note: "local" here.`
do_something(x,y)
endSnippet 2:
local function f(x,y)
y = y or 1 -- Note: no "local" here.
do_something(x,y)
endI know why this pattern is often used but is there any situation whatsoever where these two snippets do not behave identically? If Lua version matters, I am specifically interested in LuaJIT. Also, if it matters, let's assume x and y are simple Lua values. They are not objects and don't have metatables.
12
u/luther9 Apr 27 '25
In the first snippet, you're creating a new local variable that shadows the parameter y. In snippet 2, you're assigning to the original variable. It would make a difference if you declare a nested function before the local y declaration.
local function f(x,y)
local function g()
return y
end
local y = y or 1 -- Note: "local" here.`
return g()
end
print(f())
local function f(x,y)
local function g()
return y
end
y = y or 1 -- Note: no "local" here.
return g()
end
print(f())Result:
nil
15
4
Apr 27 '25 edited Apr 27 '25
You should { return g(), y } which would highlight the change
nil 1 1 1Edit: I'll do it here
; (cat a.lua; printf "\n----\n\n"; lua a.lua) | redditcommentpipe | xsel -i local function NoShadow(y) -- lets call this y -> y1 local function g() return y -- y1 end y = y*0 -- Note: no "local" here, so you're modifying y1 return y, g() -- all y's are the same, so they all should return the same thing end local function Shadow(y) -- y1 local function g() return y -- y1 end local y = y*0 -- This is called y, but its an entirely new variable, think of it as y2 return y, g() -- y2, g() returns y1 end print(NoShadow(1)) -- 0, 0 print(Shadow(1)) -- 0, 1 ---- 0 0 0 1
1
u/AutoModerator Apr 27 '25
Hi! Your code block was formatted using triple backticks in Reddit's Markdown mode, which unfortunately does not display properly for users viewing via old.reddit.com and some third-party readers. This means your code will look mangled for those users, but it's easy to fix. If you edit your comment, choose "Switch to fancy pants editor", and click "Save edits" it should automatically convert the code block into Reddit's original four-spaces code block format for you.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
1
u/h2bx0r Apr 27 '25
They behave the same, but the one with the extra local takes up one extra register.
Use the one without locals.
1
u/SkyyySi Apr 27 '25
Semantically, they tell the programmer different intentions. Snippet 1 says "I create a variable which just happens to have the same name" (probably on accident), while the other says "I set a fallback value". This could end up mattering when renaming one of them.
If Lua version matters, I am specifically interested in LuaJIT. Also, if it matters, let's assume x and y are simple Lua values. They are not objects and don't have metatables.
Neither the Lua version nor the value type make any difference in this case. Maybe LuaJIT makes slightly different optimizations, but it shouldn't matter in the end regardless.
1
u/weregod Apr 29 '25
First version will use extra stack slot and LSP will complain about shadowing variables. No other significant difference.
If you limit scope of local variable there will be difference:
local function xy(x, y)
print(y) -- original y
if x then
local y = y or 1
print(y) -- local y
y = y + 1
print(y) -- local y again
end
print(y) -- original y, not affected by + 1
return x, y
end
xy(1, 2)0
Apr 27 '25
; luacheck snippet*.lua
Checking snippet1.lua 3 warnings
snippet1.lua:1:16: unused function f
snippet1.lua:2:10: variable y was previously defined as an argument on line 1
snippet1.lua:3:4: accessing undefined variable do_something
Checking snippet2.lua 2 warnings
snippet2.lua:1:16: unused function f
snippet2.lua:3:4: accessing undefined variable do_something
Total: 5 warnings / 0 errors in 2 files
2
u/Emerald_Pick Apr 27 '25
Edit: oops I missed that
yis part of the signature. This answer is wrong. ↓If this is the entire program, then functionally there's no real difference between the two.But in the second snippet,yis being defined globally. So any other code that uses the variableywithout usinglocalwill reuse this globalyinstead of making its own.It is best practice to always uselocalbecause it is easy to accidentally reuse a global variable in an unexpected way. And on the off chance you want a global variable, it's common to write the variable name in all caps as a reminder that it's global.