I was delighted today to discover that I could add “copy” and “unpack” methods to vector and matrix Codea objects doing:
-- patch copy and unpack methods onto vec2's metatable
local mt = getmetatable(vec2())
mt.copy = function(v) return vec2(v.x, v.y) end
mt.unpack = function(v) return v.x, v.y end
However, I also discovered that you could not do the same with the “color” object. After digging around in the runtime, it looks the reason may be that the vector and matrix objects use luaL_register instead of luaL_openlib (which color uses).
Why is color class treated differently than the other Codea classes? Would it be possible to treat it the same? Or, even better, would it also be possible for you guys to add “copy” and “unpack” methods?
That’s probably an oversight on our part. I am happy to change it, and also add native copy and unpack methods. If you could add it to the issue tracker that would be great.
@Simeon, in addition to, or as an alternative to, a
copy function, perhaps (for example)
vec4(v) could work if
v was itself the result of a
V1 = vec4(); V2 = vec4(V1)
(Update) Also, as the fourth (“w”) co-ordinate defaults to 1, perhaps this could work too:
V1 = vec3(); V2 = vec4(V1)
(2nd update) Thinking back to the redefined
math.sin() example in <a = href=“http://www.lua.org/pil/6.1.html”>Programming in Lua, perhaps what I am suggesting is not required, if a coder can do something like this:
local oldvec4 = vec4
vec4 = function (x, y, z, w)
-- enhanced vec4 code here, using oldvec4
@mpilgrem: You really want copy and unpack semantics for your native data objects in Lua. For one, what they do is really clear, and for two, they make it much easier to write generic functions for different data types (for example, I’ve written code to synthesize get/set methods for class properties, and it would be great to be able to just specify “copy” or “assign” and have the synthesizer generate methods with the appropriate behavior). I was also thinking that a “set” method would be great, that takes a parameter for each element in the data object (e.g. vec2 takes 2, matrix takes 16). Combined with an unpack method, you could assign the values of one object to another easily without creating unnecessary copies.
I’ve been wondering, @toadkick, why the userdata returned by
vec4() behave differently, in the way that you describe - I’m trying to learn more about userdata, metatables and the Codea Runtime Library.
I do not think it is to do with
luaL_register - see the latter in
luaL_openlib - see
I think it is to do with the default case implemented in the
Lget(). (In both cases,
__index is set to
Lget in the metatable for the userdata).
color defaults to
lua_pushnil(L) (put a
nil value on the stack).
vec4, on the other hand, defaults to looking up the value for the key in its metatable, and puts that on the stack.
So, you can add additional keys and values to the metatable of the userdata returned by
color(), but indexing the userdata with those keys yields
(Update) It appears to me that most of Codea’s other userdata behaves like
vec4, but that the
touch userdata behaves like
(Further update) I added a page to the wiki related to this discussion.
Ah, thanks for the info @mpilgrem. I was just guessing really, I took a cursory glance at the files and that was the first thing I noticed. Your explanation makes sense though.
Thinking further on this, the problem with the userdata returned by
color() can be fixed by attaching an enhanced function to the
__index key in the userdata’s metatable. For example:
-- Enhance the Lget function referenced by __index
-- Warning: Codea forum may not display all underscore characters below
local mt = getmetatable(color())
local oldLget = mt["__index"] -- preserve old Lget
mt["__index"] = function (t, k)
local v = oldLget(t, k) -- try the old Lget
if v then return v end -- if it works, then use it
return mt[k] -- otherwise, look in the metatable
__index is enhanced, other enhancements should work. For example:
local mt = getmetatable(color())
mt["unpack"] = function(self) return self.r, self.g, self.b, self.a end
c1 = color(255, 255, 0, 255)
print(c1:unpack()) -- generates output: 255 255 0 255
nice work @mpilgrem! This is very helpful.
@mpilgrem I should have changed color to look up unknown keys in its metatable. This is something I’d still like to change.
Seems to be fixed for both color and touch in current 1.4.5 version so workaround is no longer required Also updated wiki (https://bitbucket.org/TwoLivesLeft/codea/wiki/CodeaUserdefinedTypes)