Page 1 of 3
clasp - tiny class library
Posted: Sun Apr 23, 2017 3:03 pm
by evölbug
Yes, yes I know, there are a ton of class libraries out there, some good, some bad, to each their own. None of them quite felt good to me, so I made my own. This is a simple and clean class library. It uses c-style syntax and, while I know this is Lua and some may scream at this heresy, I think it looks better than adhering to Lua's functionlike approach (although you can still use it).
It does simple singular inheritance and metamethods declaration in class (using a separate table). No super, instead you call superclass methods explicitly, passing self as first argument.
Here's the github link and usage:
https://github.com/evolbug/lua-clasp
wiki link too:
https://love2d.org/wiki/clasp
Code: Select all
class = require "clasp"
-- Basic class
Vector = class {
isVector = true; -- static values
init = function(self, x, y) -- initializer function
self.x = x
self.y = y
end;
}
a = Vector(10, 10)
print('Vector:', a.x, a.y, a.isVector) -- "Vector: 10 10 true"
Code: Select all
-- Inheritance
Vector3 = Vector:extend {
init = function(self, x, y, z) -- function overriding
Vector.init(self, x, y) -- superclass method call
self.z = z
end;
}
b = Vector3(1, 2, 3)
print('Vector3:', b.x, b.y, b.z, b.isVector) -- "Vector3: 1 2 3 true"
Code: Select all
-- Metamethods
Point = class {
init = function(self, x, y)
self.x, self.y = x,y
end;
__ = { -- metamethod table
tostring = function(self)
return 'Point('..tostring(self.x)..', '..tostring(self.y)..')'
end;
};
}
c = Point(15, 25)
print(c) -- "Point(15, 25)"
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 6:16 pm
by airstruck
Not bad, looks similar to a solution I've used before (particularly "extend"). A few thoughts:
- Setting everything to weak keys seems suspicious/unnecessary, why do that?
- Calling pairs every time you instantiate a class is slow, can that be moved to declaration from instantiation?
- The js-style constructors that can return something other than the instance are interesting, be sure to document that behavior.
- Maybe add something like
members = members or {} to also support the "not-c-style" more cleanly.
Regarding "pairs," you could get rid of it by using _meta as the metatable instead of copying everything over.
Code: Select all
local meta = self.__meta or {}
meta.__index = self
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 6:51 pm
by evölbug
- Setting everything to weak keys seems suspicious/unnecessary, why do that?
I saw some class library use weak keys, so I put them in too, dunno if it changes much really, removed it because keeps the code shorter
- Calling pairs every time you instantiate a class is slow, can that be moved to declaration from instantiation?
pairs() is called only for and if metamethods are defined in the class, and no it can't be moved, copying is necessary or it creates a metatable mess. haven't figured out how to do it without pairs yet, and why the mess is created otherwise
- The js-style constructors that can return something other than the instance are interesting, be sure to document that behavior.
they don't return anything, constructor - init() is called by `new` class system function and disregards it's return value. I noticed the problem in the code and fixed
- Maybe add something like members = members or {} to also support the "not-c-style" more cleanly.
added this one
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 7:05 pm
by evölbug
here's visible difference in using copying(current method) vs referencing (suggested) respectively
- difference.png (9.76 KiB) Viewed 8120 times
the problem makes itself apparent when inheriting which is shown above
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 7:07 pm
by airstruck
Not sure how that happened, I just tried this and it seems to work ok:
Code: Select all
return function (members)
local cls = {}
function cls.new (self,...)
local meta = self.__meta or {}; meta.__index = self; self.__meta = nil -- this changed
local object = setmetatable({}, meta)
return object.init and object:init(...) and object or object
end
function cls.extend(base,members) return setmetatable(members,{__index=base,__call=cls.new}) end
return setmetatable(members or {},{__index=cls,__call=cls.new})
end
Haven't inspected it closely though, just tested that it works with the __tostring example from the readme.
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 7:10 pm
by evölbug
well, it technically "works", but try using this dump method to check the resulting structure of an inheriting class
Code: Select all
function indent(depth)
local s = ''
for i=0,depth do s=s..' ' end
return s
end
function dump(table, label, depth)
local depth = depth or -1
local label = label or tostring(table)
print(indent(depth)..label..' {')
for k,v in pairs(table) do
if type(v) == 'table' and depth<8 then
dump(v, k, depth+1)
elseif depth<8 then
print(indent(depth+1)..k..': '..tostring(v))
else
return
end
end
if getmetatable(table) then
dump(getmetatable(table), '__meta__', depth+1)
end
print(indent(depth)..'}')
end
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 7:14 pm
by airstruck
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 7:17 pm
by evölbug
that's because you aren't inheriting
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 7:22 pm
by airstruck
Ahh, I see what you mean. Try meta = rawget(self, '__meta') or {}
Re: clasp - 13 lines of class
Posted: Sun Apr 23, 2017 7:29 pm
by evölbug
rawget() doesn't work at all, in fact it breaks metamethods