Sign in to follow this  

(Solved) Lua user data and properties (__index/metatables)

This topic is 4373 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a class design that includes a lookup table based property system. It allows me to get/set members by name in C++, during serialization, scripting, at run-time, etc. Using Lua light user data and method/meta tables on the C++ side, I can fully access objects and properties in script like this: local s = anObject:getProperty("speed"); anObject:setProperty("speed", 10); Extending that using __index or __newindex, I can do this: anObject.speed = 10; But I can't get this to work: local s = anObject.speed; It never calls the function to retrieve my property's value. If anyone can help, I'll mail you $5 or at least be really thankful. [Edited by - BeastX on December 22, 2005 9:52:20 AM]

Share this post


Link to post
Share on other sites
That code is pretty irrelevent. All it does is grab the user data pointer and variable name from Lua. Then it does a lookup for the requested property to get or set it.

The same C-functions are used for __index and __newindex as getProperty and setProperty respectively.

It just doesn't work in the __index case. I think I've read that it had something to do with light user data not invoking __index. But, I've also read that it's supposed to call it every time.

Either way, all I need is a way to get the dot operator to trigger my get/set functions properly for user data.

--I hate this but it works
object1:setProperty( "red", object2:getProperty( "red" ) * 0.5 );

--I also hate this but it works
object1.red = object2:getProperty( "red" ) * 0.5;

--I love this but it fails to invoke __index for object2.red
object1.red = object2.red * 0.5;

Anyone?

Share this post


Link to post
Share on other sites
I flipped through Programming with Lua to see if they cover light userdata.
It's in 28.5.

"Despite their common name, light userdata are quite different from full userdata. Light userdata are not buffers, but single pointers. They have no metatables."

Which is odd because you said it works for certain metamethods as expected.

A possible solution could be to create a table to act as a proxy. You could just attach your metatable to overload __index/__newindex, store the light userdata to your C++ object as a field in the table, and have the table operate on the light userdata.

Share this post


Link to post
Share on other sites
It isn't light user data, I was tired and mistyped. It's full user data, consisting of a pointer to my object.

After experimenting and enlightening research, the obvious was discovered.

I'm using the common approach of creating a library and metatable, then pointing the metatable's __index and __metatable methods to the library methods like in this example:

http://lua-users.org/wiki/UserDataWithPointerExample

I'm obviously already overriding __index with my method table. __newindex remains intact.

If I remove all the stuff from the example and override __index and __newindex directly, then I have the desired functionality for the dot operator.

BUT all functions are also passed to __index, where an error occurs. I tried catching the function and calling it manually or pushing the c-function but the stack isn't setup for the function call. So, I probably did that part incorrectly.

I need to be able to do the following, where objectA is full user data:

objectA:setActive(0);
objectA.x = objectA.x + 2;

This requires __index, __newindex, and method calling.

Share this post


Link to post
Share on other sites
Got it. The problem did revolve around the fact that I was assigning __index to be the method table for objectified calling "objectA:doStuff()".

Using this approach, there was no obvious solution to making user data support methods and members.

Backtracking, I just override __index and __newindex for my user data, so that I could access my properties.

Then some research showed me how to correctly call a function using the provided key. I acquire my user data's associated metatable and pass the key directly to it, which calls the function if it exists.

The result meant I only needed one function table for methods and events (operators) for all objects of that type.

After some optimization, this is a generic solution that friggin rocks!

Within the scripts, I'll still advise caching lookups for performance but that's the same in any language.

Share this post


Link to post
Share on other sites

This topic is 4373 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this