I hope this message finds you well.
I am developing a lua <-> C++ binding (like the several other that exist), and I've made significant headway into getting a very performant and easy to use wrapper. My final challenge in increasing the performance comes from trying to make basic "variable" get/sets on userdata made by C code work.
The Question: Is there a way to get the original object that a lookup was performed on in a cascading series of `__index` queries? Right now, lua hands you the current object in the `__index` cascade that lookup failed on and the key name it is trying to find. This is all well and good and based on the specification, but my problem is that I want what the original lookup failed on (e.g. the userdata that started it all, in my case).
This tree might help explain what my dilemma is (pseudo code):
myuserdata -- userdata
myuserdata.mt.__index -- table
myuserdata.mt.__
index.mt -- second metatable
mysuserdata.mt.__index.mt.__index -- function that performs variable lookup
When I do
myuserdata.x -- cascades down to second function, but the provided "lookup failed" argument is userdata.mt.__index, the table, not myuserdata. How do I get to 'userdata' ?
Details: I used to have it working by overriding the `__index` metamethod of the userdata and then connecting a C function to it. The C function had a list of all the functions and variables for that type, and dispatched accordingly. Because the `__index` lookup failed on the userdata's metatable (I only had 1 metatable on the userdata), I would get the userdata as the "lookup failed on this" object. Calling my C function to get either a variable (instance.a) or a function (instance:bark) had worked because I could establish the proper context with the userdata and go forward. Unfortunately, this approach was about ~2x slow thanks to having to route requests through the C function, taking a significant performance hit to not just looking up member variables but calling member functions from lua that showed heavily in all benchmarks.
I made things faster by changing the userdata's metatable to a table instead of a C function. The table had all of the non-metamethods that I wanted to provide for the userdata I had created in C. This worked, but I still needed something to hold the variables that would get found eventually by an `__index` call. I did not mind if variable getting/setting was slow, as most people using the framework use member functions and expect those to be performant.
So, I made a metatable and then put all of the variables in a C function that I linked on that metatable's `__index` method. I think set this secondary, variable-lookup metatable to the I then linked this The problem is now that I get the table as the "lookup failed on this" object, meaning I cannot get the userdata and appropriately substitute the "get/set" syntax style.