This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
tesla1889's profile picture

[WIP][difficulty: high] Defining Classes in Lua (Improved OOP)

Started by tesla1889, 30 January 2013 - 03:17 PM
tesla1889 #1
Posted 30 January 2013 - 04:17 PM
How to Use Metatables to Accomplish Complex Tasks

With a Brief Intro to Abstractions


FILE1: class.lua
Spoilerlocal 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]
end

PART1: So what does this all mean?
SpoilerThe 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]
Dlcruz129 #2
Posted 30 January 2013 - 04:20 PM
Use
 and 
.
tesla1889 #3
Posted 30 January 2013 - 04:36 PM
Use
 and 
.

then i can't indent, which is a royal pain for me

believe me, i tried it
theoriginalbit #4
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
tesla1889 #5
Posted 30 January 2013 - 05:51 PM
typing in spaces is too much of a pain
theoriginalbit #6
Posted 30 January 2013 - 05:55 PM
thats copy paste from my text editor.
Dlcruz129 #7
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.
remiX #8
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
tesla1889 #9
Posted 31 January 2013 - 07:44 PM
–snippity snip–
If that doesn't work, at least use spoilers.

thanks!
Cas #10
Posted 07 February 2013 - 05:34 AM
Nice one, looking for this for a long time.
CoolisTheName007 #11
Posted 07 February 2013 - 06:44 AM
__gc only works for userdata, which does not exists in CC. Just pointing out.
tesla1889 #12
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!
LuaEclipser #13
Posted 17 February 2013 - 03:39 PM
my head hurts…..
Pharap #14
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*