WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Accessing Global Data (https://www.wowinterface.com/forums/showthread.php?t=45150)

Elderin 11-14-12 03:36 PM

Accessing Global Data
 
Let me begin by stating that I have a MyAddon.xml file and a MyAddon.lua file that are properly aware of and function correctly with each other. Additionally, the xml file defines the UI and the lua file contains needed functions, variables, etc.

My assumption: The names of Frame and FontString entities which are defined in my xml file are available as global variables.

The answer to my question is more likely about convention. It seems that within the lua file, after things are loaded, etc., I can access the Frame objects or Fontstring objects directly by name and perform associated functions such as shown below:
Code:

in xml
<FontString inherits="GameFontNormal" name="MyFontStr_1" text="Title x">
...
</FontString>

in lua file
MyFontStr_1:SetText("Title One");
_G.MyFontStr_1:SetText("Title One");
_G["MyFontStr_1"]:SetText("Title One");
getglobal("MyFontStr_1"):SetText("Title One");

I am aware that the _G methods seem to be replacements for getglobal(). And, I also see that using any of the last three allows me to dynamically create the name of the object
Code:

local x = 1;
_G["MyFontStr_"..x]:SetText("Title "..x);

It appears that the four methods shown all change the text value of the FontString object. The question is: Functionaly, are there any differences? Any reason to use one over the other? Or, is it just whatever I myself am comfortable with?

While I have used a FontString as the example of my question, I also assume that these different approachs could be applied to any of the global data that is present at run time.

Dridzt 11-14-12 04:12 PM

Unless you are trying to modify/revive an existing addon in which case you may want to avoid an extensive re-write,
it's best if you use the frame manipulation API both to create and script your frames from lua, without using xml.

As to your actual question.
#4 is deprecated and should not be used (it means Blizzard can disable it at their convenience since they've warned it's to be phased out)
#3 and #2 are equivalent, the difference is only in style as long as the key to the table is a contiguous string.
If you had spaces in the name then table["two words"] needs to be used t.two words will not work.
#1 makes an implicit lookup in the global table but is otherwise the same as #2 and #3.

Torhal 11-14-12 04:13 PM

You shouldn't use getglobal(), as it's not only deprecated but is now actually a function-wrapper around _G and is thus actually slower due to the overhead of the function call.

The rest are functionally equivalent, the main difference being syntactic sugar. The only time I use _G["whatever"] is when I am passing in an unknown string (as through a function parameter) or constructing a string; otherwise I use _G.whatever.

Edit: Damn it, Dridzt! :)

semlar 11-14-12 04:16 PM

The getglobal function is deprecated and shouldn't be used for anything. In terms of performance you're essentially looking up "getglobal" in _G in the first place, then the overhead of a function call plus another lookup in _G for whatever you're trying to access.

I personally just use the variable name when I need to access it with two exceptions. If I have a variable with the same name in a more local scope and need to get to the global I would use _G["var"], and if I need to dynamically create the variable name I could concatenate the key together.

_G.var is just syntactic sugar for _G["var"].

SDPhantom 11-14-12 05:30 PM

Quote:

Originally Posted by Elderin (Post 268874)
Code:

MyFontStr_1:SetText("Title One");
_G.MyFontStr_1:SetText("Title One");
_G["MyFontStr_1"]:SetText("Title One");
getglobal("MyFontStr_1"):SetText("Title One");


Quote:

Originally Posted by Dridzt (Post 268876)
#1 makes an implicit lookup in the global table but is otherwise the same as #2 and #3.

As stated, #2 and #3 are exactly the same in both function and performance, however #1 is faster since it only requires a single index operation. #2 and #3 have to index _G from the global environment, which is a reiteration of itself, then index MyFontStr_1 from the resulting table. This requires 2 indexing operations and is therefore much slower in comparison. Note the number of indexing operations are measured before the processing of FontString:SetText(), which adds a couple more indexing operations to it (one to check the FontString table and the other to default into its metatable).

To break down the use of each, #1 is best if you need to access just one object directly. #3 would be for dynamically accessing from a list of objects in which you need to apply values to a name in order to construct it. #2 has no practical use. It has nothing more to offer than #1 and uses up more CPU to process for the same result.

Elderin 11-14-12 05:40 PM

Thanks, all.

Quote:

Originally Posted by Dridzt (Post 268876)
Unless you are trying to modify/revive an existing addon in which case you may want to avoid an extensive re-write, it's best if you use the frame manipulation API both to create and script your frames from lua, without using xml.

It seems like I read somewhere that Blizz preferred UI definitions in the separate xml file. However, most books on addons are relatively few and older now. I recently read on a forum that it was considered better and more elegant to do it all in lua now. When it comes to coding, I am all about elegant. However, I am currently working on a project based on a quite old addon long since not supported. And so, trying not to do a complete rewrite even though much does not resemble the original stuff and so far, I have added a lot. Perhaps my next iteration will be doing away with the xml file.

Thanks, again, guys.

Seerah 11-14-12 05:52 PM

Right - Blizz prefers to do it that way. But they don't care how you do it. ;)

The only time you really need XML is if you are defining a template to use and a frame-factory type function won't suffice.

SDPhantom 11-14-12 09:53 PM

Most people prefer to use Lua over XML. I really don't see any proof either way on long term performance impacts. The idea was that XML was for static UI structures while you'd use Lua for creating dynamic frames. With nearly everything being supported in Lua, pretty much everyone has phased out XML. I think the tree-like XML structure is easier to read and understand in this fashion than lines of linear Lua code. That's just my preference though. It's up to you to decide which way you want to go.

Vlad 11-15-12 02:09 AM

Shame we can't write templates using lua. ;)

Phanx 11-15-12 02:15 AM

The biggest problem with XML is that it's incredibly verbose, and is just a hassle to write by hand.

Also, using XML, all references must be global, which is another big argument against it. While in Lua you can write:

Code:

local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", MyAddOn.EventHandler)

... if you're using XML, you have to create 1-3 globals and 1-2 functions to achieve the same thing.

Firstly, you have to give the frame a global name, or you won't be able to access it from your Lua code.

Secondly, you have to create an anonymous function to register the event in an OnLoad script, or a global function to be assigned as the OnLoad script.

Finally, you either have to make MyAddOn.EventHandler a global function outside of the MyAddOn table (eg. instead of function MyAddOn:EventHandler() ... end you'd need function MyAddOn_EventHandler(MyAddOn) ... end) or double up on function calls by creating another anonymous wrapper function:

Code:

<Frame name="SomeGlobalSpam">
        <Scripts>
                <OnLoad>
                        self:RegisterEvent("ADDON_LOADED")
                </OnLoad>
                <OnEvent>
                        MyAddOn:EventHandler(event, ...)
                </OnEvent>
        </Scripts>
</Frame>


SDPhantom 11-15-12 05:26 AM

If you really want XML code to be inaccessible to the global environment, you can clean up after registering a script handler. Furthermore, the following XML structure can be rewritten to use one less stack position in its script handlers.

Code:

<Frame>
        <Scripts>
                <OnUpdate>
                        MyAddonFrame_OnUpdate(self,elapsed);
                </OnUpdate>
        </Scripts>
</Frame>

Rewritten to:

Code:

<Frame>
        <Scripts>
                <OnUpdate function="MyAddonFrame_OnUpdate"/>
        </Scripts>
</Frame>

This takes the pointer set to the global MyAddonFrame_OnUpdate and directly sets it as the OnUpdate handler instead of creating a function wrapper. After that, you may erase the global variable and the frame will still run the function.

Elderin 11-15-12 11:41 PM

First, Phantom, I assume all references to OnLoad should be replaced with OnUpdate. Otherwise, I am a bit lost.

However. in the first part of your example it is fairly obvious that the OnUpdate function is being passed two arguments - self and elapsed - explicitly.

In the rewritten version, where only the function name is declared, do we know what parameters the function will actually receive?

semlar 11-15-12 11:59 PM

It receives all the arguments attached to the event.

In your lua file you would just have something like
lua Code:
  1. function MyAddonFrame_OnUpdate(self, elapsed) etc. end

SDPhantom 11-16-12 12:30 AM

Quote:

Originally Posted by Elderin (Post 268962)
First, Phantom, I assume all references to OnLoad should be replaced with OnUpdate. Otherwise, I am a bit lost.

I chose to use the OnUpdate handler in the example at random. The function property is available to all script handler tags. The post was to demonstrate a flexibility in the XML schema and not actual code to use.



Quote:

Originally Posted by Elderin (Post 268962)
However. in the first part of your example it is fairly obvious that the OnUpdate function is being passed two arguments - self and elapsed - explicitly.

In the rewritten version, where only the function name is declared, do we know what parameters the function will actually receive?

The second method receives all values through the function's argument list, just like any other function in Lua. See Widget handlers for a complete list of all script handlers for every widget and the order of their arguments passed. Note using this method, you can assign different names to the arguments if you wish. It doesn't change the functionality any.

Phanx 11-16-12 02:53 AM

Quote:

Originally Posted by Elderin (Post 268962)
I assume all references to OnLoad should be replaced with OnUpdate.

No. Those are separate scripts, with totally different purposes. The OnLoad script is only called once, after all of the frame's XML is read. The OnUpdate script is called every time a new video frame is drawn, so potentially 100+ times every second.

It's also worth mentioning that OnLoad scripts are unnecessary in Lua, and in fact aren't even supported in Lua; you just declare the frame and then do stuff with it immediately.

Elderin 11-16-12 06:36 AM

Sorry, guys, I was just looking at the specific code in the example. I was just referring to the mix of tags and functions. I just confused things with my statement about changing the Onload (magenta colored) to OnUpdate (green colored). My bad. I apologize.

Quote:

Originally Posted by SDPhantom (Post 268911)
If you really want XML code to be inaccessible to the global environment, you can clean up after it in an OnLoad handler. Furthermore, the following XML structure can be rewritten to use one less stack position in its script handlers.

Code:

<Frame>
        <Scripts>
                <OnUpdate>
                        MyAddonFrame_OnUpdate(self,elapsed);
                </OnLoad>
        </Scripts>
</Frame>

Rewritten to:

Code:

<Frame>
        <Scripts>
                <OnUpdate function="MyAddonFrame_OnUpdate"/>
        </Scripts>
</Frame>

This takes the pointer set to the global MyAddonFrame_OnLoad and directly sets it as the OnLoad handler instead of creating a function wrapper. After that, you may erase the global variable and the frame will still run the function.

Thanks for the link to the Widget Handlers. Sigh. So much to learn, so little time.

SDPhantom 11-16-12 10:15 AM

The thinking behind the change to demonstrate with the OnUpdate handler instead was that it runs continually whereas OnLoad runs only once. This was to display the ability to delete the global and show that the handler would still run afterward. I corrected my other post to make the full switch, I thought I had caught all of the OnLoad references, but apparently, there were more. I didn't even notice until now, yesterday was an off day for me. :o

SDPhantom 11-16-12 10:21 AM

Quote:

Originally Posted by Phanx (Post 268975)
It's also worth mentioning that OnLoad scripts are unnecessary in Lua, and in fact aren't even supported in Lua; you just declare the frame and then do stuff with it immediately.

The reason for this is because the OnLoad handler fires before CreateFrame() returns. If you create a template with an OnLoad handler, then inherit it with a CreateFrame() call, it would run.


All times are GMT -6. The time now is 11:12 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI