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.
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]