WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Blizz metamethods (https://www.wowinterface.com/forums/showthread.php?t=49205)

Aanson 04-14-14 08:44 PM

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.

Lombra 04-15-14 09:29 AM

Code:

local metatable = getmetatable(CreateFrame("Frame"))
Note that each object type (Frame, Button, Slider, etc) has its own metatable.

Phanx 04-15-14 05:58 PM

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.

Aanson 04-16-14 08:27 AM

Quote:

Originally Posted by Phanx (Post 292112)
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.

jeruku 04-16-14 09:30 AM

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

semlar 04-16-14 10:26 AM

Quote:

Originally Posted by Aanson (Post 292118)
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.

ravagernl 04-16-14 11:00 AM

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.

Duugu 04-16-14 11:27 AM

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. :D

Aanson 04-17-14 05:35 AM

Thanks everyone for your advice.

Quote:

Originally Posted by semlar (Post 292123)
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.

Aanson 04-17-14 05:39 AM

Quote:

Originally Posted by ravagernl (Post 292125)
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 :)

Sharparam 04-17-14 05:52 AM

Quote:

Originally Posted by Aanson (Post 292132)
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"

Aanson 04-17-14 06:05 AM

Quote:

Originally Posted by Sharparam (Post 292134)
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?

Sharparam 04-17-14 06:07 AM

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.

Aanson 04-17-14 06:09 AM

Quote:

Originally Posted by Sharparam (Post 292136)
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 :)


All times are GMT -6. The time now is 03:14 PM.

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