4

I have objects in my C++ program that I pass to Lua as userdata, and I override the metatable for this userdata so that assignments to and from indices of the object (via __newindex and __index) result in a call to C, which converts the assignment to affect the C++ object or convert the C++ element to a Lua value (either another userdata or a base type like bool, number, string). The userdata is passed in as arguments to event-like Lua functions that are called from my C++ program.

luaL_newmetatable(L, "object");
lua_pushstring(L, "__index");
lua_pushvalue(L, -2);  /* pushes the metatable */
lua_settable(L, -3);  /* metatable.__index = metatable */

luaL_openlib(L, NULL, vallib_m, 0);
luaL_openlib(L, "internal", vallib_f, 0);

lua_pushstring(L, "__index");
lua_pushstring(L, "get");
lua_gettable(L, 2);  /* get val.get */
lua_settable(L, 1);  /* metatable.__index = val.get */

lua_pushstring(L, "__newindex");
lua_pushstring(L, "set");
lua_gettable(L, 2); /* get array.set */
lua_settable(L, 1); /* metatable.__newindex = val.set */

However, this doesn't allow me to assign the actual variable itself, only an index of the variable. There is no meta-event for directly overriding the assignment operator, so I am looking for a workaround.

In other words, I can do this: lua_userdata_object_passed_as_arg_to_event["is_it_true"]=true and it assigns the Lua boolean to my internal C++ object, but if I do this: lua_userdata_object_passed_as_arg_to_event = new_object() it will change what the Lua variable references, but it won't do anything to the core object as I understand it.

One workaround I've considered is some hack requiring developers to do lua_userdata_object_passed_as_arg_to_event["__self"] = new_object() if they want to change the object itself, but this is undesirable.

So I've found some unique solutions to overriding the assignment operator by using global variables and overriding the global metatable assignment operators, but I am looking to see if anyone can help me expound this solution. See http://lua-users.org/lists/lua-l/2012-01/msg00413.html and https://www.lua.org/pil/14.2.html. In particular, my variables are function arguments, not globals, so how can I convert to globals through the C API so that any assignments will be captured by a custom C function that will take action if the assignment is happening to a global userdata?

By the way, my userdata is a pointer to an object to avoid duplicating large objects, if that matters.

Lars
  • 233
  • 2
  • 9

1 Answers1

5

Lua and C/C++ are different languages with different needs. In C/C++, a variable always references a specific object. You can change the contents of this object, but you can never make a variable deal with a different object. If you do a = b;, you are copying the value of b into a. You can never change what object a is talking about.

In Lua, variables do not permanently reference anything. Thus, there is a distinction between the object the variable currently holds and the value of that object.

Your kludge via global variables functions, but local variables are things that don't really exist. They're locations on the Lua stack; you can't override Lua's default behavior with regard to them.

The best way to handle this is to accept the difference between C and Lua. Write code in Lua the way you would write code in Lua. Don't try to make Lua code work like C; that way is folly. They are different languages, and you should embrace their differences, not work against them.

If you want to give Lua the ability to do the equivalent of a = b, then you should create a function in your type called assign or something that will allow you to assign to the object's value. Just like if you want to copy all of the table elements from one table to another, you have to write a function to do that.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • The goal of the question is to make Lua user-friendly, and as I stated, there is only one remaining piece left to the puzzle: adding function arguments from C to the global variable metatable in the current Lua context. I believe this is possible, but have only seen the various components necessary scattered in widely different applications, so I am trying to piece them together. If it isn't possible, then yes, I will do something like declare assign() in a library or use a custom index like "__self"... – Lars Aug 16 '16 at 22:35
  • @Leo: "*The goal of the question is to make Lua user-friendly*" But Lua *is* "user-friendly" already. What it isn't is "exactly equivalent to C/C++". If you want to pass function parameters as globals of some kind and retrieve them in functions, you can. But in Lua, they won't look like function arguments. And it still doesn't change the fact that arbitrary `local` variables cannot participate in this. – Nicol Bolas Aug 16 '16 at 22:39