Log In  


Based off of this code posted by this nice gentleman: https://github.com/jonstoler/class.lua

I made some small adjustments so I could have headache-free classes and inheritance in my project.

classdef = {}

-- default (empty) constructor
function classdef:init(...) end

-- create a subclass
function classdef:extend(obj)
	local obj = obj or {}

	local function copyTable(table, destination)
		local table = table or {}
		local result = destination or {}

		for k, v in pairs(table) do
			if not result[k] then
				if type(v) == "table" and k ~= "__index" and k ~= "__newindex" then
					result[k] = copyTable(v)
				else
					result[k] = v
				end
			end
		end

		return result
	end

	copyTable(self, obj)

	obj._ = obj._ or {}

	local mt = {}

	-- create new objects directly, like o = Object()
	mt.__call = function(self, ...)
		return self:new(...)
	end

	-- allow for getters and setters
	mt.__index = function(table, key)
		local val = rawget(table._, key)
		if val and type(val) == "table" and (val.get ~= nil or val.value ~= nil) then
			if val.get then
				if type(val.get) == "function" then
					return val.get(table, val.value)
				else
					return val.get
				end
			elseif val.value then
				return val.value
			end
		else
			return val
		end
	end

	mt.__newindex = function(table, key, value)
		local val = rawget(table._, key)
		if val and type(val) == "table" and ((val.set ~= nil and val._ == nil) or val.value ~= nil) then
			local v = value
			if val.set then
				if type(val.set) == "function" then
					v = val.set(table, value, val.value)
				else
					v = val.set
				end
			end
			val.value = v
			if val and val.afterSet then val.afterSet(table, v) end
		else
			table._[key] = value
		end
	end

	setmetatable(obj, mt)

	return obj
end

-- set properties outside the constructor or other functions
function classdef:set(prop, value)
	if not value and type(prop) == "table" then
		for k, v in pairs(prop) do
			rawset(self._, k, v)
		end
	else
		rawset(self._, prop, value)
	end
end

-- create an instance of an object with constructor parameters
function classdef:new(...)
	local obj = self:extend({})
	if obj.init then obj:init(...) end
	return obj
end

function class(attr)
	attr = attr or {}
	return classdef:extend(attr)
end

Basically I've changed the bits where it says Class to classdef. The whole thing eats up about 350 tokens, I'm not sure how to go about optimising it as I only have a yellow belt in Lua-fu. I ran it in a cart and it seems to work so far.

I'm posting this because when I looked for advice on defining a class in pico 8, a lot of people were creating copies of functions and stuffing them into tables. Expensive, but easy - maybe too easy. Or people would go the other way and do the setmetatable boilerplate code for every class and extended class. Efficient but ugly.

I've done most of my Lua coding so far using Codea on the iPad. It has a built in class() function that behaves just like the one above. So much easier than trying to understand metatables, and it can sit in its own tab. It also does some wacky getter / setter stuff that I'm not sure I need, but I might abuse it at some point.

If you can point out any immediate problems with the code (as in certain parts will break in pico 8) or optimisations I'd be very grateful. Other class implementations are welcome too.

2


if obj.init then obj:init(...) end

do you need the conditional here? unless someone intentionally sets subclass.init=nil, won't obj:init always resolve back up to the default empty classdef.init?



[Please log in to post a comment]