Thread Tools Display Modes
02-05-24, 04:32 PM   #1
Benalish
A Flamescale Wyrmkin
 
Benalish's Avatar
Join Date: Dec 2012
Posts: 123
Dealing with templates and OOP

This is the first time I try to apply OOP in Lua. My goal is to create a template as if it were an object, without using the mixin.

XML code:

Code:
<Frame name="TemplateListViewTemplate" virtual="true">		
	<Scripts>
		<OnLoad>
			self = LibUnitScanListView:New(self)
		</OnLoad>
	</Scripts>
</Frame>
Lua code:

Lua Code:
  1. LibListView = {}
  2.  
  3. function LibListView:New(self)
  4.        
  5.         local listviewmt = {
  6.             buttons  = {},
  7.             data = {},
  8.             --more methods and functions
  9.             SetWidgetScript = function(words) print(words) end,
  10.         }
  11.         setmetatable(self, { __index = setmetatable(listviewmt, getmetatable(self)) })
  12. end

If I write

Lua Code:
  1. self = LibListView:New(self)
inside <OnLoasd> tag the code works fine. At this point, I would like to make sure that the class is created without passing self as a parameter: in short, using the wording
Lua Code:
  1. listview = LibListView:New()
to make the code more elegant.
I tried to not put self in the signature, just leaving it without any params:
Lua Code:
  1. function LibListView:New()
At this point an error emerges:


Lua Code:
  1. listview = CreateFrame("Frame","listview",UIParent,"TemplateListViewTemplate")
  2. listview:SetSize(150, 100)
  3. listview:SetPoint("TOPLEFT",50,-75)
  4. listview:SetWidgetScript("Hello World")
returns this error:

attempt to call method 'SetWidgetScript' (a nil value)

Can you help me?

Last edited by Benalish : 02-05-24 at 05:27 PM.
  Reply With Quote
02-05-24, 08:31 PM   #2
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
The way Lua handles obj.method() vs obj:method() is simple, but not straightforward.
When calling a function, obj:method(...) is the same as obj.method(obj,...).
When defining a function, obj:method(...) is the same as obj.method(self,...).

Lua will handle mixing these syntaxes as long as you take the above rule in mind.
If you call obj.method(frame), a function defined as obj:method() will receive frame and put it in self.

One way or another, you need a reference to your frame to work on it. The WoW API doesn't set any globals when a frame script runs.



The way I would implement your code with this in mind and make room for easier expansion:
Lua Code:
  1. --  __mode defines whether (k)eys and/or (v)alues are released to the GC if this table is the only remaining reference to them (in either case, the entire table entry is removed)
  2. --  Frames can't be garbage collected, but it's still good practice for memory management if you're storing external objects
  3. local OriginalMeta=setmetatable({},{__mode="kv"});
  4.  
  5. --  ListView frame metatable set to refer to its original metatable as a fallback (Stored by LibListView:New())
  6. local ListViewMeta={__index=setmetatable({},{__index=function(obj,key) return OriginalMeta[obj][key]; end})};
  7.  
  8. LibListView={};
  9. function LibListView:New()--    self is our new frame (call as LibListView.New(frame))
  10.     assert(OriginalMeta[self]==nil,"Already attached to frame");
  11.     OriginalMeta[self]=getmetatable(self);--    Store original metatable as a fallback
  12.     setmetatable(self,ListViewMeta);--  Set new metatable
  13.  
  14.     self:Initialize();
  15. end
  16.  
  17. --  Frame methods injected by our library
  18. function ListViewMeta.__index:Initialize()
  19. --  Initialize instanced data and store to frame
  20.     self.Buttons={};
  21.     self.Data={};
  22. end
  23.  
  24. function ListViewMeta.__index:SetWidgetScript(something)
  25.     print(something);
  26. end

OnLoad Handler:
Code:
LibListView.New(self)
Test Script:
Lua Code:
  1. local listview = CreateFrame("Frame","listview",UIParent,"TemplateListViewTemplate")
  2. listview:SetSize(150, 100)
  3. listview:SetPoint("TOPLEFT",50,-75)
  4. listview:SetWidgetScript("Hello World")



One major change was to separate your static functions and instanced data. The frame methods were moved to their own metatable and are injected into the frame. As the frame is basically a table itself, data values are written directly into it.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Dealing with templates and OOP


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