clasp - tiny class library

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
evölbug
Prole
Posts: 38
Joined: Wed Dec 21, 2016 12:58 pm
Contact:

Re: clasp - 8 lines of class

Post by evölbug » Mon Apr 24, 2017 4:52 am

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.

User avatar
evölbug
Prole
Posts: 38
Joined: Wed Dec 21, 2016 12:58 pm
Contact:

Re: clasp - 8 lines of class

Post by evölbug » Mon Apr 24, 2017 5:20 am

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.
perf.png
perf.png (13.95 KiB) Viewed 2506 times

User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: clasp - 8 lines of class

Post by airstruck » Mon Apr 24, 2017 5:48 am

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

User avatar
evölbug
Prole
Posts: 38
Joined: Wed Dec 21, 2016 12:58 pm
Contact:

Re: clasp - 8 lines of class

Post by evölbug » Mon Apr 24, 2017 6:31 am

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.

User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: clasp - 8 lines of class

Post by bartbes » Mon Apr 24, 2017 5:50 pm

Please stop double-posting...

User avatar
raidho36
Party member
Posts: 1951
Joined: Mon Jun 17, 2013 12:00 pm

Re: clasp - 8 lines of class

Post by raidho36 » Mon Apr 24, 2017 9:18 pm

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.

User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: clasp - 8 lines of class

Post by airstruck » Tue Apr 25, 2017 2:07 pm

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

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 })
This stuff shouldn't be that hard; I don't know if you posted here to get feedback or just to announce it, 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.

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.

User avatar
evölbug
Prole
Posts: 38
Joined: Wed Dec 21, 2016 12:58 pm
Contact:

Re: clasp - 8 lines of class

Post by evölbug » Tue Apr 25, 2017 6:30 pm

I posted it for both feedback and announcement, and really thanks for all the suggestions and inspiration.
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.
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.

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 })
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.
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!
newclasp.png
Object difference between new and old clasp
newclasp.png (12.03 KiB) Viewed 2407 times

User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: clasp - 8 lines of class

Post by airstruck » Tue Apr 25, 2017 6:53 pm

This won't work if proto isn't passed in, because objectmeta's __index will be nil.

Code: Select all

    local objectmeta = {__index = proto}
    local proto = setmetatable(proto or {}, -- ...
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.

User avatar
evölbug
Prole
Posts: 38
Joined: Wed Dec 21, 2016 12:58 pm
Contact:

Re: clasp - 8 lines of class

Post by evölbug » Tue Apr 25, 2017 7:06 pm

oh, missed about the proto, fixed it and clumped the lines more, now it's 4

thanks for the tests!

Post Reply

Who is online

Users browsing this forum: Majestic-12 [Bot] and 4 guests