tags:

views:

85

answers:

5

I was perusing an Lua code file, and the very top of the file contains:

    1  | TradeSkillFrameReset = TradeSkillFrame_LoadUI;
    2  | 
    3  | TradeSkillFrame_LoadUI = function()
    4  |    TradeSkillFrameReset();
            ...
    112|    TradeSkillFrame_LoadUI = TradeSkillFrameReset;
            ...
    114| end;

The very first line they are doing an assignment:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

At this point in the code file they are assigning an undeclaraed identifier (TradeSkillFrame_LoadUI) to an undeclared variable (TradeSkillFrameReset). Is this allowed in Lua?

  • is variable declaration implicit?
  • are all undeclared identifiers assumed to be forward declarations?

The more confusing thing is that the first TradeSkillFrame_LoadUI seems to do is call itself:

TradeSkillFrame_LoadUI = function()
   TradeSkillFrameReset();

How is this not an infinite loop?


Edit: Added remaining references to TradeSkillFrameReset and TradeSkillFrame_LoadUI.

A: 

On the first line, since TradeSkillFrame_LoadUI is a non-initialized variable, then this first line:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

Is the same as making:

TradeSkillFrameReset = nil

The function below that doesn't enter an infinite loop because TradeSkillFrameReset isn't actually 'pointing to anything' there.

My guess is that later on in the code, it gets properly initialized. Like so:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

TradeSkillFrame_LoadUI = function()  -- 1. function declaration
   TradeSkillFrameReset();

   [...snip...]
end;

[... snip ...]
TradeSkillFrameReset = somethingElse -- 2. initialized to something else
TradeSkillFrame_LoadUI()             -- 3. function invocation

The trick is that you can define a function on 1, and use the value of a variable on 3, while changing it on 2.

Let me know if this is not clear enough.

egarcia
A: 

I would guess its doing something similar to Javascript's function hoisting, which you can read about here: http://stackoverflow.com/questions/1710424/referencing-a-javascript-value-before-it-is-declared-can-someone-explain-this

Frank Schwieterman
lua does no such thing.
daurnimator
A: 

Unless the behavior of global variables has been modified in the environment that you're using has been modified, the statement does absolutely nothing.

local TradeSkillFrameReset = TradeSkillFrame_LoadUI

Would have an effect, creating a local variable "slot" and making code past that point use the local variable slot for TradeSkillFrameReset rather than doing a global variable lookup for it. However, as it is in the code you posted, it simply assigns the global variable to nil, which has the effect of erasing it, in other words, no effect if it was already nil.

Reasons it could be there:

1) The environment the code is running in does something special when a global variable assignment is done, rather than the default behavior of a simple assignment. I don't think this is likely though, as if there was any special behavior the lookup of the nil TradeSkillFrame_LoadUI would probably cause an error.

2) The most probable reason is simply for readability. It's to let you know that TradeSkillFrameReset will be properly assigned to later buried somewhere in the code where you won't notice it as readily.

Stravant Rae
+5  A: 

If TradeSkillFrame_LoadUI is a global function, the first statement captures this function in TradeSkillFrameReset.

The assigment to TradeSkillFrame_LoadUI then replaces the global function with a new one, that at first calls the original function through the TradeSkillFrameReset reference.

This pattern is called "function hooking", here is some more information about the general technique and some World of Warcraft Lua environment specific details (where this script may come from, according to the function's name)

Some example code, to make this clear:

function SomeGlobalFunction()
    print("I'm the original global function")
end

OrigFunction = SomeGlobalFunction

SomeGlobalFunction = function()
    OrigFunction()
    print("And here's the modfied one...")
end

--...
SomeGlobalFunction()

this will print the following output:

I'm the original global function

And here's the modfied one...

As a side note, Lua's name is not all capitalized.

DerKuchen
You are right. i was googling for `TradeSkillFrameReset` and finding nothing. Even though the function `TradeSkillFrame_LoadUI` is declared there, it's given the same name as a globally available function. Running a google search for `TradeSkillFrame_LoadUI` confirmed it. So it is hooking/overriding.
Ian Boyd
I'd note too, that localising the stored function is probably a good idea.
jsimmons
@jsimmons :Why is it a good idea? What's the point?
Ian Boyd
Not localising it means it's put into global scope, it has the same drawbacks as every global. Added to that there is a performance gain by using locals over globals.
jsimmons
A: 

The main thing to take away is that it's easy for Lua code to inject global variables into other Lua code. I've used a lot of Lua where they use the environment to add global vars. Just because a var isn't defined in that file most assuredly does not mean that it does not exist. It doesn't even have to be defined as a global variable in another file, because you can inject into the environment table programmatically as if it were any other table.

DeadMG