Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Anyone who can explain this Lua behavior? — Gideros Forum

Anyone who can explain this Lua behavior?

SnowThiefSnowThief Member
edited May 2013 in General questions
local MyFunction = function(a) return 999 end
local MyFunction = function(a) if a < 100 then return MyFunction(a*2) else return a end end

print(MyFunction(1))

Can you guess the output? The answer is 999.

local MyFunction = function(a) return 999 end
MyFunction = function(a) if a < 100 then return MyFunction(a*2) else return a end end

print(MyFunction(1))

What about this? All I did was remove "local" from the redefinition of MyFunction() and since the function has already been declared as local, that shouldn't matter, right? Well, it does, because now the output is 128.

What's going on?

Comments

  • zvardinzvardin Member
    My guess is it ignores the second declaration. A variable should only be declared once and then assigned from that point on.
  • bowerandybowerandy Guru
    edited May 2013
    @SnowThief, it doesn't ignore the second declaration, it's just that while the second function is being compiled the previous declaration is still in force. That way, when you call MyFunction(a*2) you are really calling the first function. Adding some print statement should show what is going on:
    local MyFunction = function(a) print("there") return 999 end
    local MyFunction = function(a) print("here") if a < 100 then return MyFunction(a*2) else return a end end
     
    print(MyFunction(1))
    Only when the entire function has been compiled does it actually get assigned to the variable (local or global).

    @zvardin, it is perfectly legal to redefine, either variables or functions in Lua and it is quite often rather useful.

    best regards
  • I don't really like using
    local x = function() end
    Sometime it doesn't give a good result for me also (function not being called, and other bad things)

    instead i did something like this

    local function MyFunction(a) return 999 end
    local function MyFunction(a) if a < 100 then return MyFunction(a*2) else return a end end
  • john26john26 Maintainer
    This is a good reason to only use local at the beginning of a function, like in C programming. In your example its easy to see that the two local commands next to each other are a problem but if you had

    local foo=2
    :
    -- lots code
    :
    local foo=1

    you would not notice the error.
  • SnowThiefSnowThief Member
    edited May 2013
    Only when the entire function has been compiled does it actually get assigned to the variable (local or global).
    Then why does the second "local" keyword make a difference?
  • ar2rsawseenar2rsawseen Maintainer
    edited May 2013
    @SnowThief when you redefine function with local it needs to be compiled again, whereas if you don't use local second time it only gets reassigned and is available to use immediately

    or something along those line :)
  • bowerandybowerandy Guru
    edited May 2013
    @SnowThief, I think it is because Lua treats local and global variables differently. See here:

    http://www.lua.org/pil/6.2.html

    I think when the compiler sees a global variable name that is not yet defined, it creates an empty named slot for it immediately. Hence in the recursive call when the second function is global it already knows that MyFunction exists and just calls through it. Since globals are really just fields in a table this probably applies to functions stored in all table fields too.

    Local variables, being held on the stack are probably just artefacts of the compiler, which is which they are handled differently. As the above article suggests, you can't have a recursive call through a local without first forward referencing it. Recursive calls through globals are okay without the forward reference though.

    best regards
  • There are no global variables in the examples, though, bowerandy, only local.

    local a = 1;
    a = 2; -- Still the same, local variable. NOT a new, global variable.
  • bowerandybowerandy Guru
    edited May 2013
    @SnowThief, oh yes, you're right.

    In which case I don't know the answer. However, the two examples are not equivalent. In the first you are defining two variables it is just that the scope of the second overrides the first. In the second case you have one local that gets reassigned.

    best regards
  • zvardinzvardin Member
    @bowerandy very interesting, but when is it more useful to do that?
    local a = function() return 1 end
     
    --why would it be more useful to redeclare entirely using the local keyword?
    a = function() return 2 end
  • @zvardin, I don't think it is useful to redefine locals.

    However, I can think of several situations where redefining table or global variables is useful. Typically that is the way you can hook into existing behaviour and extend it. The GiderosCodingEasy library by @ar2rsawseen does it a lot.

    best regards
  • zvardinzvardin Member
    Ah ok, I thought so, but was curious from the previous comment. Thanks!
  • OZAppsOZApps Guru
    edited May 2013
    @snowThief

    Here's a stab at things... It's all about chunks and closures, the way Lua handles things.
    twitter: @ozapps | http://www.oz-apps.com | http://howto.oz-apps.com | http://reviewme.oz-apps.com
    Author of Learn Lua for iOS Game Development from Apress ( http://www.apress.com/9781430246626 )
    Cool Vizify Profile at https://www.vizify.com/oz-apps
  • @SnowThief, oh yes, you're right.

    In which case I don't know the answer. However, the two examples are not equivalent. In the first you are defining two variables it is just that the scope of the second overrides the first. In the second case you have one local that gets reassigned.
    @bowerandy, you are correct about what happens; in the first case another local variable is created with the same name, but the body of the function keeps reference to the earlier variable as you described. Note that while the functions *seem* to have the same name, they actually do reference two different functions with two different values.

    In the second case ("local foo = function() end; foo = function() ... end") the same (local) variable gets a new value and the function call references the same variable,
    so it all works. By the time when the function is called, there is only one variable that has the function value (so it becomes a recursive function).

    I've answered a somewhat similar SO question last month (http://stackoverflow.com/a/15867293/1442917) that covers another syntax that has a subtle difference: "local function foo() end" is NOT the same as "local foo = function() end" because the first one allows "foo" to be referenced from the body of the function (new name effectively becomes "visible" to the function), while in the second case if "foo" is referenced, it will use whatever value was assigned to "foo" previously (local, upvalue, or global).

    Paul.
  • @bowerandy, you are correct about what happens; in the first case another local variable is created with the same name, but the body of the function keeps reference to the earlier variable as you described.
    Shouldn't there then be an optional "global" keyword for when you want to create a new global variable with the same name? I mean, then it would be consistent with how it works for "local".
Sign In or Register to comment.