This function creates simple extensible 'types' with a few additional (potentially) handy properties. If you find it useful, help yourself to it. Credit appreciated but not required.
You use it like this:
-- a 2d point object point = new_type('x y') -- argument names separated by spaces p = point(1, 2) print(p.x) -- prints 1 print(p.y) -- prints 2 |
As for the handy properties, the first is that the object's data is stored both by key and as an array. Which means you can access the properties using the dot notation, numerical indexes, or even unpacking the object, all of which can come in handy in different situations.
p = point(1, 2) x, y = unpack(p) -- extract all the data in order -- all of these print 1 print(p.x) print(p[1]) print(x) -- and all of these print 2 print(p.y) print(p[2]) print(y) |
The downside of this is that each object is storing the data twice and, therefore, requires twice as much space. So if you have a lot of active objects in your program at once you'll run out of memory about twice as fast. But you can always modify new_type()
to only use one or the other of these methods instead of both if you prefer.
The second handy property is that functions created with new_type()
aren't actually functions, they're objects which you can add methods to. Those methods are then available to every object of that 'type'. For instance:
point = new_type('x y') point.add = function(a, b) return point(a.x + b.x, a.y + b.y) end p = point(1, 2) q = point(2, 3) r = p:add(q) print(r.x) -- prints 3 print(r.y) -- prints 5 |
It even works if the methods are defined after you've already created the objects:
point.dot_product = function(a, b) return a.x * b.x + a.y * b.y end print(p:dot_product(r)) -- prints 13 |
Here's another version of the same thing. This one uses more tokens (99) but avoids duplicating the data in each object and therefore also avoids the duplicate data getting out of sync with itself:
-- 99 tokens function new_type(names) local names = split(names, ' ') local meta = {} local key_map = {} for i=1,#names do key_map[names[i]] = i end return setmetatable( meta, { __call=function(self, ...) local obj = {...} return setmetatable( obj, { __index=function(self, i) if meta[i] then return meta[i] else return self[key_map[i]] end end, __newindex=function(self, key, value) if type(key) == 'string' then rawset(self, key_map[key], value) else rawset(self, key, value) end end } ) end } ) end |
So now you can change the object via the named property or the numerical index and you're actually just changing the same piece of data in either case:
point = new_type('x y') p = point(1, 2) print(p.x) -- prints 1 print(p[1]) -- prints 1 p.x = 7 print(p.x) -- prints 7 print(p[1]) -- prints 7 p[1] = 4 print(p.x) -- prints 4 print(p[1]) -- prints 4 |
[Please log in to post a comment]