🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Bug in Lua

Started by
8 comments, last by Krun 19 years, 10 months ago
Hi! The folowing script works fine: function Main() -- This function gets called first Step1() end local function Private() end function Step2() Private() end function Step1() Step2() end When I move the definition of Private between Step1 and Step2: function Main() -- This function gets called first Step1() end function Step2() Private() end local function Private() end function Step1() Step2() end I get a "Attempt to call global 'Private' (a nil value)". Shouln't Lua work fine with late definitions (calling Step1 in Main works)?
Advertisement
It seems that any late-defined local function will cause this error. The following won't work either:

function Main()
Private()
end

local function Private()
end

But if you define Private before Main, it will work.
Quote: Original post by Krun
But if you define Private before Main, it will work.


I think this is how is supposed to work

Alberto
-----------------------------The programming language Squirrelhttp://www.squirrel-lang.org
Quote: Original post by fagiano
I think this is how is supposed to work


But why? Local variables don't have to be predefined so why do functions? This caused a lot of problems for me until I figured out the reason.
Variables and functions are quite different things. The variable gets created with the given name when you assign something to it. However a function needs to be defined so that Lua knows how to handle it - for instance, how to process the argument list that you pass it, and how the return value(s) will be assigned.
Quote: Original post by Krun
Local variables don't have to be predefined so why do functions?


Whenever you define a function, you also define a variable that holds it. The next two function definitions are identical:

function identity (x)     return x endidentity = function (x)     return xend


Likewise, local functions define a local variable and assign the function value to it.

local function identity (x)     return x endlocal identity = function (x)     return xend


There is no difference between regular variables and function names:

myprint = printprint = 45myprint (print)   ==>  45myprint (tostring (myprint))  ===>   function ********


Which brings us to the visibility of local variables versus global variables. Local variables have "lexical scoping". They are only visible from their definition point until the end of the current block:

function foo ()    print ("global access to x  : " .. x)    local x = 45     print ("local access to x : " .. x)    do       local x = "foobar"       print ("local access to x (inner block) : " .. x)    end    for x =1,3 do        print ("local access to x (loop) : " .. x)    end    print ("local access to x : " .. x)endx = 100foo () ===>global access to x  : 100local access to x : 45local access to x (inner block) : foobarlocal access to x (loop) : 1local access to x (loop) : 2local access to x (loop) : 3local access to x : 45x = 25foo ()===>global access to x  : 25local access to x : 45local access to x (inner block) : foobarlocal access to x (loop) : 1local access to x (loop) : 2local access to x (loop) : 3local access to x : 45




Does this make things clearer? local variables are only visible in their block (which may be an entire file) from their declaration point onwards. Anywhere else you can only access the global variable.

By the way, a file you execute with dofile, or a string you execute with dostring first gets compiled to an anonymous function without parameters. So when you execute scripts you can imagine the whole script being wrapped in a function definition, which is then executed:

function ()  -- your script goes here, function definitions and allend ()


All the local variables you declare inside the script are by definition _not_ visible outside. Which is pretty much the point of having local variables in the first place.

Your problem (in the other thread) is rather strange to begin with. You want your scripts to have functions with identical names, and still be able to execute the functions of all those scripts. But how are you going to know which scripts function you are actually executing?

Well, if you don't actually care, you can create tables that hold all the functions from all the scripts, and you can access them from those tables. Then Each script would do something like:

OnLoaded = Onloaded or {} table.insert (OnLoaded,   function ()     -- your code goes here  end)
Even better, suppose you have a number of scripts and you want to execute a global "Finalize" function in each of those scripts when you quit your application.

In each of your scripts you can check whether a "Finalize" global function already exists, and, if it exists, call it within the new global Finalize function you define in this new script:

-- save the global Finalize function in a local variablelocal saveFinalize = Finalize-- the function definition overwites the global Finalize functionfunction Finalize ()    -- do finalize stuff you want  if saveFinalize then  -- if a Finalize function existed before    saveFinalize ()  -- then call it  endend


This way a single call to Finalize from your C code will launch all the Finalize code in all of your scripts.
I think I'll handle the problem by loading a xml file instead of loading a script directly. The file would look like this

<scripts>
<script name="TheScriptName" src="PathToScript" onloaded="NameOfOnLoadedFunction"/>
<script name="TheScriptName2" src="PathToScript2" onloaded="NameOfOnLoadedFunction2"/>
</scripts>

This way every script will have a diferently named OnLoaded function and the engine will still know which one to call.

Thanks.
Why use xml? Lua is a better data description language anyway.

scripts = {{name="TheScriptName", src="PathToScript", onloaded="NameOfOnLoadedFunction"},{name="TheScriptName2", src="PathToScript2", onloaded="NameOfOnLoadedFunction2"}}
I'm using xml for some other stuff so it's not a problem, but I might consider using lua. I think it would be very simple in combination with luabind::get_globals

This topic is closed to new replies.

Advertisement