Page 1 of 3

### clasp - tiny class library

Posted: Sun Apr 23, 2017 3:03 pm
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

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

### Re: clasp - 13 lines of class

Posted: Sun Apr 23, 2017 7:05 pm
here's visible difference in using copying(current method) vs referencing (suggested) respectively
difference.png (9.76 KiB) Viewed 3937 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
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
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
I get the exact same structure... https://hastebin.com/movahoyisi.lua

### Re: clasp - 13 lines of class

Posted: Sun Apr 23, 2017 7:17 pm
that's because you aren't inheriting

### Re: clasp - 13 lines of class

Posted: Sun Apr 23, 2017 7:22 pm
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
rawget() doesn't work at all, in fact it breaks metamethods