Thread Tools Display Modes
04-14-14, 08:44 PM   #1
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Blizz metamethods

Hey all,

How can I get a reference to the metatable which is used by all frames created ingame ( which contains Show, SetClampedToScreen, IsObjectType etc etc )?

Only reason I ask is because I wouldn't mind adding a few of my own methods.

If I can't do that, I'll just add the methods to each frame directly, but it seems daft having to replicate them each time.

Cheers for any advice.
__________________
__________________

Last edited by Aanson : 04-14-14 at 08:51 PM.
  Reply With Quote
04-15-14, 09:29 AM   #2
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Code:
local metatable = getmetatable(CreateFrame("Frame"))
Note that each object type (Frame, Button, Slider, etc) has its own metatable.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
04-15-14, 05:58 PM   #3
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
That said, there's really no reason to meddle with the Blizzard metatable. It's absolutely trivial to add methods to a frame, and you don't have to "replicate" anything; definte each method once, and just add a pointer to each frame as desired:

Code:
local function DoSomething(frame)
    -- do something with the frame
end

for i = 1, 100000 do
    _G["MyButton"..i].DoSomething = DoSomething
end
Obviously you don't (I hope) have 100000 buttons, but the principle is the same. It doesn't matter how many frames you attach the function to; only one copy of the function exists.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
04-16-14, 08:27 AM   #4
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Originally Posted by Phanx View Post
That said, there's really no reason to meddle with the Blizzard metatable. It's absolutely trivial to add methods to a frame, and you don't have to "replicate" anything; definte each method once, and just add a pointer to each frame as desired:

Code:
local function DoSomething(frame)
    -- do something with the frame
end

for i = 1, 100000 do
    _G["MyButton"..i].DoSomething = DoSomething
end
Obviously you don't (I hope) have 100000 buttons, but the principle is the same. It doesn't matter how many frames you attach the function to; only one copy of the function exists.


In the above example, the function is replicated and _G["MyButton"..i].DoSomething is not a pointer to the locally defined function 'DoSomething', it's a separate copy of the function. That's what I had meant by 'replicate'.

I confirmed this with the following test...

Lua Code:
  1. local self = CreateFrame();
  2.  
  3. local function TestFunction()
  4.   print("Hello");
  5. end
  6.  
  7. self.TestFunction = TestFunction;
  8.  
  9. self:TestFunction(); -- obviously results in output: "Hello";

if you then change the locally defined function to print("Goodbye") and call self:TestFunction() again, it'll still output "Hello".


Regardless, I've added the methods to the frames directly anyway, although I see no harm what-so-ever in 'meddling' with (ie adding methods to) Blizz's table.
__________________
__________________
  Reply With Quote
04-16-14, 09:30 AM   #5
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Perhaps you should use a function to add functions to frames.

For example:
Lua Code:
  1. end
  2. local function DoSomething(self, ...)
  3.    print("Hello")
  4. end
  5. local function DoALittleDance(self, ...)
  6.    print("Bonjour")
  7. end
  8. local function NowDoAHandStand(self, ...)
  9.    print("Aloha")
  10. end
  11. local function AddFunctionsToFrame(self)
  12.      self.func1 = DoSomething
  13.      self.func2 = DoALittleDance
  14.      self.func3 = NowDoAHandStand
  15. end
  16.  
  17. local frame = CreateFrame('Frame')
  18. local frame2 = CreateFrame('Frame')
  19.  
  20. AddFunctionsToFrame(frame)
  21. AddFunctionsToFrame(frame2)



Seeing as you were playing with code here is an example you may have missed.
Lua Code:
  1. local frame = CreateFrame()
  2.  
  3. local function TestFunction()
  4.   print("Hello")
  5. end
  6. print(TestFunction) -- prints the function identifier
  7.  
  8. frame.aFunc= TestFunction
  9. print(frame.aFunc)
  10.  
  11. frame:aFunc()
  12. TestFunction = function()
  13.   print("Goodbye")
  14. end
  15.  
  16. print(TestFunction)
  17. print(frame.aFunc) -- This will print the identifier of the original function
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison
  Reply With Quote
04-16-14, 10:26 AM   #6
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Originally Posted by Aanson View Post
In the above example, the function is replicated and _G["MyButton"..i].DoSomething is not a pointer to the locally defined function 'DoSomething', it's a separate copy of the function.
This is not correct. You can compare self.TestFunction == TestFunction in your example to see that they are references to the same function.

It sounds to me like however you were redefining the function in your test was creating a new instance of it.
  Reply With Quote
04-16-14, 11:00 AM   #7
ravagernl
Proceritate Corporis
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 1,176
ElvUI an Tukui define a "toolkit" using metamethods, i'm however not going to link or share any code because of license issues. LibCandybar also uses a metatable to add functions to a private frametype.

There is also a thread dated from 2014 on wowace.com about metamethods, one of them has an excellent example.
  Reply With Quote
04-16-14, 11:27 AM   #8
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
There's another possible way to add something as default to widgets: the XML templates.
Like this:

Code:
<Frame name="myTest" virtual="true">
        <Scripts>
            <OnLoad>
                self.print = function(...) print("it's me, the myTest template") end
            </OnLoad>
        </Scripts>
</Frame>    

local myTestFrame = CreateFrame("Frame", "myFrame", UIParent, "myTest")
myTestFrame:print()

It's not that elegant as it requires XML and code editing inside XML, but it's easy to use.

Last edited by Duugu : 04-16-14 at 05:46 PM.
  Reply With Quote
04-17-14, 05:35 AM   #9
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Thanks everyone for your advice.

Originally Posted by semlar View Post
This is not correct. You can compare self.TestFunction == TestFunction in your example to see that they are references to the same function.

It sounds to me like however you were redefining the function in your test was creating a new instance of it.
Yeah Semlar, I noticed that too after I'd written that post...

Lua Code:
  1. local function func() end
  2. local self = CreateFrame();
  3. self.func = func;
  4. print( self.func == func ); -- which returned true.

That would indicate that self.func and func both point to the same instance of the same function.

But it confuses me a little. Here's my example (and what made me think that it's actually a different instance of the same function:

Lua Code:
  1. local t, frame = {}, {};
  2. function t.func()
  3.   print("a");
  4. end
  5.  
  6. frame.func = t.func;
  7.  
  8. frame:func() -- outputs 'a'
  9.  
  10. t.func = nil; -- the original function no longer exists
  11.  
  12. frame:func() -- still outputs 'a'

So surely frame.func doesn't simply point to t.func because if that were the case, it would return an error. Wouldn't that indicate that each frame the method is added to will hold it's own instance of that method?

Just to be clear, I'm not in any way trying to insist that what I'm saying is right... to be honest, I'm stumped.

I'd always thought that one of the primary benefits of a metatable is to allow numerous objects to refer to the same instance of a method, thereby conserving memory.

If I'm looking at this all wrong, please let me know.
__________________
__________________

Last edited by Aanson : 04-17-14 at 05:46 AM.
  Reply With Quote
04-17-14, 05:39 AM   #10
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Originally Posted by ravagernl View Post
ElvUI an Tukui define a "toolkit" using metamethods, i'm however not going to link or share any code because of license issues. LibCandybar also uses a metatable to add functions to a private frametype.

There is also a thread dated from 2014 on wowace.com about metamethods, one of them has an excellent example.
Special thanks for that
__________________
__________________
  Reply With Quote
04-17-14, 05:52 AM   #11
Sharparam
A Flamescale Wyrmkin
 
Sharparam's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2011
Posts: 102
Originally Posted by Aanson View Post
Code:
t.func = nil; -- the original function no longer exists
This is not correct. By doing t.func = nil you are just making t.func no longer reference that function. Any other references to the function are still valid.

You are assigning nil to t.func, not assigning nil to the actual function stored in memory. Both t.func and frame.func are just pointers to that function.

(I could be wrong in any of my statements, someone please correct me in that case.)

Using a table as an example where you can see the change in both references (because tables are reference types in Lua):

lua Code:
  1. local t = { foo = "bar" }
  2. local a = { t = t }
  3. local b = { t = t }
  4. print(a.t.foo) -- prints "bar"
  5. print(b.t.foo) -- prints "bar"
  6. b.t.foo = "baz"
  7. print(a.t.foo) -- prints "baz"

Last edited by Sharparam : 04-17-14 at 05:58 AM.
  Reply With Quote
04-17-14, 06:05 AM   #12
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Originally Posted by Sharparam View Post
This is not correct. By doing t.func = nil you are just making t.func no longer reference that function. Any other references to the function are still valid.

You are assigning nil to t.func, not assigning nil to the actual function stored in memory. Both t.func and frame.func are just pointers to that function.

(I could be wrong in any of my statements, someone please correct me in that case.)

Using a table as an example where you can see the change in both references (because tables are reference types in Lua):

lua Code:
  1. local t = { foo = "bar" }
  2. local a = { t = t }
  3. local b = { t = t }
  4. print(a.t.foo) -- prints "bar"
  5. print(b.t.foo) -- prints "bar"
  6. b.t.foo = "baz"
  7. print(a.t.foo) -- prints "baz"
Ah okay.

Just to confirm my understanding. When I write...

t.func = nil;

... does lua check to see if the function is referenced by anything else. If it is, it keeps it, if not, it gets wiped from memory by the garbage collector?
__________________
__________________
  Reply With Quote
04-17-14, 06:07 AM   #13
Sharparam
A Flamescale Wyrmkin
 
Sharparam's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2011
Posts: 102
Pretty sure that's how it works. The garbage collector goes through objects and disposes of any that don't have any variables referencing them.
  Reply With Quote
04-17-14, 06:09 AM   #14
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Originally Posted by Sharparam View Post
Pretty sure that's how it works. The garbage collector goes through objects and disposes of any that don't have any variables referencing them.
That clears things up. Cheers
__________________
__________________
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Blizz metamethods


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off