clasp - tiny class library
Re: clasp - 8 lines of class
Reading metamethods directly from class will break their inheritance on longer chains, because pairs() doesn't read the __index tree, which is mandatory for them to be inherited correctly. Of course I could manually check for each individual metamethod to trigger __index lookup, but that'd expand the code unnecessarily, that's why I use a table, I don't think it's too much of a bother really. I'll see what I can do to move the metamethod copying to declaration. Also I've already said what I think about cycles, they will make things incredibly hard to debug if the class structure itself turns out to be flawed.
Re: clasp - 8 lines of class
I'm not that concerned about performance as it appears to be a bit faster than middleclass according to its performance test. Now, it isn't a real world scenario so I don't know if it's actually faster on heavily packed classes.
Re: clasp - 8 lines of class
That's why I'm suggesting copying them from the parent class to the subclass in "extend." The proto.__index=proto thing facilitates that (may not be necessary, but I think you'd be back to closures).evölbug wrote:Reading metamethods directly from class will break their inheritance on longer chains, because pairs() doesn't read the __index tree, which is mandatory for them to be inherited correctly
I generally agree that proto.__index=proto is annoying, and possibly more difficult to debug, but if the alternative is copying a bunch of stuff with pairs every time an object is instantiated that's pretty much a non-starter.Also I've already said what I think about cycles, they will make things incredibly hard to debug if the class structure itself turns out to be flawed.
Re: clasp - 8 lines of class
It's not so slow that I'd give up the readability of objects for a few nanoseconds of performance. Parsing the whole class structure and copying down everything on inheritance is not much better, even if it only happens once in declaration. Just 3 levels of inheritance creates an unreadable cyclic fractal that I don't want, and it grows exponentially, making it impossible to read subclasses deeper than 2 levels, even if you try to ignore cycles (which can't be done reliably because it would involve caching and ignoring values, and you would end up with only half of the structure displayed - slow, messy and you can't reliably see the whole structure).
Copying only happens within the confines of that one table, and it's only ever going to be a few elements unless you start defining things other than metamethods, besides it creates clean classes and instances in the end.
I tried moving metamethod copying outside of instance creation anyway, but I haven't figured it how to do it decently yet.
Copying only happens within the confines of that one table, and it's only ever going to be a few elements unless you start defining things other than metamethods, besides it creates clean classes and instances in the end.
I tried moving metamethod copying outside of instance creation anyway, but I haven't figured it how to do it decently yet.
- bartbes
- Sex machine
- Posts: 4946
- Joined: Fri Aug 29, 2008 10:35 am
- Location: The Netherlands
- Contact:
Re: clasp - 8 lines of class
Please stop double-posting...
Re: clasp - 8 lines of class
Classes is arguably the single heaviest used code, it's gotta be fast, period. If you need debugging version, make a separate one just for that.
Also you really need to test things like that. You can't just assume that it's faster or slower to do things certain way.
Finally, there is a saying, "he who laughs at ounces cries over pounds". It may not look like much but it all adds up.
Also you really need to test things like that. You can't just assume that it's faster or slower to do things certain way.
Finally, there is a saying, "he who laughs at ounces cries over pounds". It may not look like much but it all adds up.
Re: clasp - 8 lines of class
If by "decently" you mean "without cycles," why not move back to closed-over functions? You didn't seem to mind it before, this time you can have it use an upvalue to legitimize its existence.evölbug wrote:I tried moving metamethod copying outside of instance creation anyway, but I haven't figured it how to do it decently yet.
Code: Select all
local base = { init = function()end }
function base:extend (proto)
proto = proto or {}
local meta = { __index = proto }
for k, v in pairs(self) do if k:match '^__' and proto[k] == nil then proto[k] = v end end
for k, v in pairs(proto) do if k:match '^__' then meta[k] = v end end
return setmetatable(proto, { __index = self, __call = function (_, ...)
local object = setmetatable({}, meta)
return object, object:init(...)
end })
end
return setmetatable(base, { __call = base.extend })
Some unit tests would also be good for ensuring that it does what you think it does, and so that alternatives can be tested for compliance with however it's supposed to work.
Re: clasp - 8 lines of class
I posted it for both feedback and announcement, and really thanks for all the suggestions and inspiration.
I forgot about upvalues as I am not that familiar with the concept coming from other languages that don't have them, but I optimized your code and applied it to my previous style. I still didn't like parsing the whole class and copying down metamethods to each new subclass, as it can and most will pull any unwanted "private" data (assuming "double underscore" style for "strictly private") into metatables; it's also making subclasses larger by having duplicate methods, and also a little bit slower declaration.
This is the new and final iteration unless I or someone here finds an optimization that can be done. 2 lines less than old code.
Well, it was/is in theory ready for use, maybe some updates were needed here and there, but, if it wasn't considered ready before, I'm fairly confident the new iteration is final.but as you're aware you haven't figured out how to "do it decently" yet, it would be good to let people know that it's not ready for actual use.
I forgot about upvalues as I am not that familiar with the concept coming from other languages that don't have them, but I optimized your code and applied it to my previous style. I still didn't like parsing the whole class and copying down metamethods to each new subclass, as it can and most will pull any unwanted "private" data (assuming "double underscore" style for "strictly private") into metatables; it's also making subclasses larger by having duplicate methods, and also a little bit slower declaration.
This is the new and final iteration unless I or someone here finds an optimization that can be done. 2 lines less than old code.
Code: Select all
local base = { init = function()end; extend = function(self, proto)
local objectmeta = {__index = proto}
local proto = setmetatable(proto or {},{__index=self, __call=function(_, ...) local object=setmetatable({},objectmeta) return object,object:init(...) end})
for k,v in pairs(proto.__ or {}) do objectmeta['__'..k]=v end
return proto end }
return setmetatable(base, { __call = base.extend })
Indeed, but it's not easy writing tests that can be tested against other class frameworks and test things thoroughly and accurately enough. I will try though!Some unit tests would also be good for ensuring that it does what you think it does, and so that alternatives can be tested for compliance with however it's supposed to work.
Re: clasp - 8 lines of class
This won't work if proto isn't passed in, because objectmeta's __index will be nil.
This is why tests are important. You can use these if you want, it's very similar, just change 'constructor' to 'init' and add tests for the metamethod stuff. The script to run the tests is here (test.lua); run lua test.lua clasp-test.lua.
Code: Select all
local objectmeta = {__index = proto}
local proto = setmetatable(proto or {}, -- ...
Re: clasp - 8 lines of class
oh, missed about the proto, fixed it and clumped the lines more, now it's 4
thanks for the tests!
thanks for the tests!
Who is online
Users browsing this forum: Bing [Bot], Google [Bot] and 2 guests