404 posts
Location
St. Petersburg
Posted 30 January 2013 - 04:17 PM
How to Use Metatables to Accomplish Complex Tasks
With a Brief Intro to Abstractions
FILE1: class.lua
Spoiler
local BaseFunction = function() end
local BaseClass = setmetatable({},{
[indent=1]__class = true,[/indent]
[indent=1]__type = "class",[/indent]
[indent=1]__parent = {},[/indent]
[indent=1]__index = BaseFunction,[/indent]
[indent=1]__newindex = BaseFunction,[/indent]
[indent=1]__call = BaseFunction,[/indent]
[indent=1]__gc = BaseFunction,[/indent]
[indent=1]__metatable = true[/indent]
})
local BaseIndex = function(self,index)
[indent=1]local parent = rawget(self,"__parent")[/indent]
[indent=1]if (index == "super")[/indent]
[indent=2]then return rawget(parent,"__call")[/indent]
[indent=1]end[/indent]
[indent=1]return parent[index][/indent]
end
Class = setmetatable({},{
[indent=1]__class = true,[/indent]
[indent=1]__type = "class",[/indent]
[indent=1]__parent = BaseClass,[/indent]
[indent=1]__index = BaseIndex,[/indent]
[indent=1]__newindex = BaseFunction,[/indent]
[indent=1]__call = function(self,tClass,sType,cParent,fnCall,fnGC,fnIndex,fnNewIndex)[/indent]
[indent=2]tClass = (tClass or {})[/indent]
[indent=2]sType = (sType or "class")[/indent]
[indent=2]cParent = (cParent or BaseClass)[/indent]
[indent=2]fnCall = (fnCall or BaseFunction)[/indent]
[indent=2]fnGC = (fnGC or BaseFunction)[/indent]
[indent=2]fnIndex = (fnIndex or BaseIndex)[/indent]
[indent=2]fnNewIndex = (fnNewIndex or BaseFunction)[/indent]
[indent=2]if (type(tClass) ~= "table")[/indent]
[indent=2]or (type(sType) ~= "string")[/indent]
[indent=2]or (not rawget(cParent,"__class"))[/indent]
[indent=2]or (type(fnCall) ~= "function")[/indent]
[indent=2]or (type(fnGC) ~= "function")[/indent]
[indent=2]or (type(fnIndex) ~= "function")[/indent]
[indent=2]or (type(fnNewIndex) ~= "function")[/indent]
[indent=2]then[/indent]
[indent=3]error("class: invalid args")[/indent]
[indent=2]end[/indent]
[indent=2]return setmetatable(tClass,{[/indent]
[indent=3]__class = true,[/indent]
[indent=3]__type = sType,[/indent]
[indent=3]__parent = cParent,[/indent]
[indent=3]__index = fnIndex,[/indent]
[indent=3]__newindex = fnNewIndex,[/indent]
[indent=3]__call = fnCall,[/indent]
[indent=3]__gc = fnGC,[/indent]
[indent=3]__metatable = true[/indent]
[indent=2]})[/indent]
[indent=1]end,[/indent]
[indent=1]__gc = BaseFunction,[/indent]
[indent=1]__metatable = true[/indent]
})
local oldtype = type
type = function(obj)
[indent=1]return (rawget(obj,"__type") or oldtype(obj))[/indent]
endPART1: So what does this all mean?
Spoiler
The file, class.lua, defines a base class and a class that will create other classes. It also redefines the type function to prioritize the class type instead of the Lua type.
The classes we create are just tables with strategically defined metamethods. The library-defined metamethods used are as follows:- __index: called when a table is referenced with an index equal to nil
- __newindex: called when attempting to add an index to a table
- __call: called when a table is called like a function
- __gc: called when a table is garbagecollected
- __metatable: hides the metatable
The custom metavalues are:- __class: a boolean flag that signifies a class object
- __type: a string that is a class' type
- __parent: a pointer to the parent of a class
So, essentially, this file gave us access to the "function" Class, which returns a new specified class. [indent=1]TO DO: continue the tutorial[/indent]
1619 posts
Posted 30 January 2013 - 04:20 PM
404 posts
Location
St. Petersburg
Posted 30 January 2013 - 04:36 PM
then i can't indent, which is a royal pain for me
believe me, i tried it
7508 posts
Location
Australia
Posted 30 January 2013 - 04:38 PM
then i can't indent, which is a royal pain for me
I can indent fine
function name()
someVar = "yeh"
if someVar then
print(someVar)
end
end
404 posts
Location
St. Petersburg
Posted 30 January 2013 - 05:51 PM
typing in spaces is too much of a pain
7508 posts
Location
Australia
Posted 30 January 2013 - 05:55 PM
thats copy paste from my text editor.
1619 posts
Posted 31 January 2013 - 04:12 AM
I believe indentation only gets copied when you hit the light switch in the corner that takes you to full view. If that doesn't work, at least use spoilers.
2088 posts
Location
South Africa
Posted 31 January 2013 - 06:29 AM
Click on the top left button "Toggle Editing Mode" and then it will keep intendation.
Spoiler
local BaseFunction = function() end
local BaseClass = setmetatable({},{
__class = true,
__type = "class",
__parent = {},
__index = BaseFunction,
__newindex = BaseFunction,
__call = BaseFunction,
__gc = BaseFunction,
__metatable = true
})
local BaseIndex = function(self,index)
local parent = rawget(self,"__parent")
if (index == "super") then
return rawget(parent,"__call")
end
return parent[index]
end
Class = setmetatable({},{
__class = true,
__type = "class",
__parent = BaseClass,
__index = BaseIndex,
__newindex = BaseFunction,
__call = function(self,tClass,sType,cParent,fnCall,fnGC,fnIndex,fnNewIndex)
tClass = (tClass or {})
sType = (sType or "class")
cParent = (cParent or BaseClass)
fnCall = (fnCall or BaseFunction)
fnGC = (fnGC or BaseFunction)
fnIndex = (fnIndex or BaseIndex)
fnNewIndex = (fnNewIndex or BaseFunction)
if (type(tClass) ~= "table")
or (type(sType) ~= "string")
or (not rawget(cParent,"__class"))
or (type(fnCall) ~= "function")
or (type(fnGC) ~= "function")
or (type(fnIndex) ~= "function")
or (type(fnNewIndex) ~= "function") then
error("class: invalid args")
end
return setmetatable(tClass,{
__class = true,
__type = sType,
__parent = cParent,
__index = fnIndex,
__newindex = fnNewIndex,
__call = fnCall,
__gc = fnGC,
__metatable = true
})
end,
__gc = BaseFunction,
__metatable = true
})
local oldtype = type
type = function(obj)
return (rawget(obj,"__type") or oldtype(obj))
end
404 posts
Location
St. Petersburg
Posted 31 January 2013 - 07:44 PM
–snippity snip–
If that doesn't work, at least use spoilers.
thanks!
1 posts
Posted 07 February 2013 - 05:34 AM
Nice one, looking for this for a long time.
302 posts
Posted 07 February 2013 - 06:44 AM
__gc only works for userdata, which does not exists in CC. Just pointing out.
404 posts
Location
St. Petersburg
Posted 07 February 2013 - 08:34 AM
__gc only works for userdata, which does not exists in CC. Just pointing out.
damn. rewrite of all of my projects commences!
233 posts
Location
Cleveland, Ohio
Posted 17 February 2013 - 03:39 PM
my head hurts…..
839 posts
Location
England
Posted 06 March 2013 - 03:51 PM
damn. rewrite of all of my projects commences!
I feel your pain. How much I would love to have access to debug and gc…
Anyway, if I write OO stuff in lua, I tend to have a dispose/finalise function to get rid off all the no longer needed stuff.
CC lua also doesn't appear to respect the supposed '70 local variables only' thing I've heard about in other lua implementations.
Surprisingly a lot of lua implementations don't adhere to the standard. Legend Of Grimrock's stuff doesn't give you access to _G, setfenv or getfenv as far as I can tell.
*end rambling*