Lua - References to Functions Within Tables - c++

If I have a global table Table that has functions getValue(), setValue(), etc. Can I store a reference to Table.getValue or do I have to store a reference to Table and then call the member functions?
lua_getglobal(L, "Table");
lua_getfield(L, -1, "getValue");
getValueRef = luaL_ref(L, LUA_REGISTRYINDEX);
lua_getfield(L, -1, "setValue");
setValueRef = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pop(L, 1); // Pop "Table" off of the stack

There is no such thing as a "member function" in Lua. There is simply a function, which is a value. You can store functions anywhere, directly in the global table, in some other table you create, etc. Functions (and all Lua values for that matter) have no association with any table they happen to be stored in.
If you want to store a function somewhere (and creating a "reference" is nothing more than storing it somewhere), you can.
FYI: it is not a good idea to directly use the registry for Lua "references". I'd suggest creating a table you store in a particular slot in the registry to use for your references. Of course, I would say that it's not a good idea to use "references" for what you're doing period.

You can always create a "bound" function as a closure:
local tbl=Table
local function TableGetValue(key)
return tbl:getValue(key)
end
do_stuff_with(TableGetValue)

Related

What is the difference between Lua registry with light userdata and references?

So with the Lua C API you can save a Lua value in the registry and retrieve it later. There are different ways to do it, you can create a variable and use it's pointer as the key in the registry as it's always unique. You would push the pointer as light userdata.
You can also create a reference using LuaL_ref(L, LUA_REGISTRYINDEX). What is the advantage of one over the other? When to use references and when to use pointers?
Also with references, as it is called a reference, if the Lua garbage collector collects the Lua value, will the value in the registry be nil? What if Lua updates the Lua value, will the value in the registry also change?
Lua registry is just another lua table, easily accessible via predefined "special" index. I guess you don't need explanations on how Lua table is different from light userdata.
It doesn't really matter how you will index registry table, as long as you can store that key on C/C++ side. For your convenience there's already functions (luaL_ref/luaL_unref) giving you integer key that is easy to store and move around.
About garbage collection - rules are always the same. As long as value is stored in table that wasn't marked as weak table (registry is not weak table), that value won't be cleared. You must explicitly remove value from the registry.
Changing value will obey normal Lua rules. Assigning new immutable value to some variable won't change value stored in registry, i.e. registry won't follow updates to some variable. But changing content of mutable value (table etc) is ok, since registry and variable will refer same value.
In addition to previous answer:
Differences between Lua lightuserdata and userdata
lightuserdata is a special Lua type (as well as nil, boolean, number, string, table, thread etc.) containing C pointer. Nothing more. You can't assign metatable to lightuserdata. On the contrary, you can assign metatable to userdata type. For example see Lua File operations, where file handle is userdata with methods. f:read("*all") f is userdata the command is equivalent to f.read(f, "*all")
Indexing LUA_REGISTRYINDEX with integer or C pointer
There are two methods that are widely used on registry table.
Create new reference to Lua value with luaL_ref and store the return integer value somewhere in your code. I.e. to access the Lua value you'll need to read C variable holding the reference and index registry table with lua_rawgeti(L, LUA_REGISTRYINDEX, i) where is that integer value. lua_rawseti(L, LUA_REGISTRYINDEX, i) is also possible, but don't try rewrite to a nil value with this method!
You creating a static C variable static int myvar; and then use lua_rawgetp(L, LUA_REGISTRYINDEX, &myvar) and lua_rawsetp(L, LUA_REGISTRYINDEX, &myvar) for manipulation of stored Lua value straight-forward.
Unfortunately I can't compare the performance of both methods. I think they are almost the same.

Override Assignment Operator in Lua with C API

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.
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.

Lua get function from argument

A simple example of producing.
protocol.onConnect(function() end, function () end, ...)
Now in c, i want to get the functions which are in args #1, #2.
In strings, numbers,... we can get them using (lua_getstring,..), But I at-least didn't found how to get a function.
int luaProtocolOnConnect(lua_State* L)
{
int base_func // func #1
int call_func // func #2
....
}
You cannot really "get" a Lua function. Lua functions, like Lua tables, are pure-Lua objects. As such, they have no C or C++ analog. If you want to call a Lua function, that's done through lua_call, lua_pcall or similar functions. This is done in-situ on the Lua stack.
So you can't take a Lua function and turn it into a C++ value. What you can do is take a Lua function and manipulate it in the various ways that all Lua objects can be manipulated.
For example, let's say you want to store a Lua function in a C++ object, then later call whatever Lua function was stored there. Well obviously, you can't convert the Lua function directly into a C++ value. What you can do is store that Lua function in a place which C++ can access. You use some value which does have a C++ analog to reference that stored Lua function. The value must be unique for every object you want to store like this. The value you get when storing the object will be saved in your C++ object. When the time comes to retrieve the Lua function, you simply use the stored value to retrieve it.
Because this is an exceedingly common operation, Lua has ways to facilitate this. The first is the Lua registry, a table that C++ can access but Lua code cannot (not unless you give it access).
The second is the luaL_ref series of functions. luaL_ref takes whatever is at the top of the stack and sticks it in a table you provide, returning to you an integer key that can be used to retrieve it later. lua_rawgeti can be used to retrieve the function from the table by the key, and luaL_unref takes the table and the integer key, removing the referenced function from the table when you're done with it.
So if you want to store such functions, you simply need to create such a table, stick it in a known place in the registry (so that you can fetch it whenever you need to), and then use luaL_ref to store those functions. When it comes time to call them, retrieve them with lua_rawgeti. When you're finished using them, destroy them with luaL_unref.
You can use lua_isfunction to check if it's a function, use lua_pushvalue to push its value on top of the stack and then use luaL_ref (luaL_ref(L,LUA_REGISTRYINDEX);) to turn it into a unique key you can later reference to retrieve the value (lua_rawgeti(L,LUA_REGISTRYINDEX,ref)) and call the function.

Will repeatedly passing a table to a function allocate more memory?

i have a function in Lua that operates on a table, repeatedly adding entries to the table:
function DoStuff()
local table = {};
for i = 1, 1000 do
local name, value = GetSomething(i);
if (CheckSomething(name, value))
table[name] = value
end;
end;
end;
i know this is fast; Lua has a good hash table algorithm. But now i need to split out part of my function, so i may unit test it:
function DoStuff()
local table = {};
for i = 1, 1000 do
local name, value = GetSomething(i);
--split out checking so it's testable
table = ParseTheThing(table, name, value);
end;
end;
i know that Lua does not support passing paramters by reference, instead if i need to add an item to my table, Lua will make a copy and i must return that copy:
--Core checking function
function ParseTheThing(table, name, value)
if (CheckSomething(name, value))
table[name] = value
end;
return table;
end;
So it seems to me that every time i call CheckSomething Lua will create another table, that needs to be garbage collected.
Or maybe not. Maybe Lua does support passing parameters by reference, and i can simply call:
ParseTheThing(table, name, value);
--Core checking function
function ParseTheThing(table, name, value)
if (CheckSomething(name, value))
table[name] = value
end;
end;
Will Lua's garbage collector be forced into doing a lot more work if i refactor my code as i have done?
Notes:
Don't confuse the simplified example used in the question with the question i'm asking.
i don't have any way to measure memory usage, or number of collections, so i cannot try it.
I know that Lua does not support passing paramters by reference
The term "by reference" is overloaded, causing a lot of confusion (especially in the Java world where I've seen people refuse to acknowledge that one of the meanings even exists).
Passing by reference can mean:
Passing the location of an object in memory, rather than the object itself. This is what is meant by "pass by reference" in C. In this sense, Java does pass by reference, and so does Lua for many of its types (userdata, tables, etc.).
An alias for a variable, such that any modifications to the alias is reflected in the original. This goes beyond simply not passing by value; if the variable holds a location of an object, you can assign a different location through the alias. You can't do this for #1, where you pass a reference to an object, not a variable. These types of references are supported in C#, C++, etc., but not C or Lua.
More simply:
Pass by value: The object in the calling function is a copy of the object received by the called function.
Pass by reference^1: The object in the calling function can be modified by the called function.
Pass by reference^2: The variable in the calling function can be modified by the called function.
instead if i need to add an item to my table
Just pass the table -- a reference, not a copy, is passed.

Tracking Lua tables in C

I have C++ objects and I have Lua objects/tables. (Also have SWIG C++ bindings.)
What I need to be able to do is associate the two objects so that if I do say
CObject* o1 = getObject();
o1->Update();
it will do the equivalent Lua:
myluatable1.Update();
So far I can imagine that CObject::Update would have the following code:
void CObject::Update(){
// Acquire table.
// ???
// Do the following operations on the table.
lua_getfield(L, -1, "Update");
lua_pcall(L, 0, 0, 0);
}
How would I store/set the Lua table to be used, and what would go in the // ??? above to make the Update call work?
I cant believe nobody noticed this!
http://www.lua.org/pil/27.3.2.html
A section of the Lua API for storing references to lua objects and tables and returning references for the purposes of being stored in C structures!!
I am curious for the reasons of this "reverse SWIG"...
The objects in Lua live within the Lua contexts, so at a minimum you would need to store "L" inside your object.
The issue of passing the "table pointer" is a bit more delicate - even though Lua allows to retrieve the pointer off the Lua stack (using lua_topointer()), there is no way of putting that back. Understandingly - because otherwise one would also need to check that the pointer does point to a valid object, etc, etc.
What you might do however, is to store the references to the tables in the global table, the index being the lightuserdata being the pointer to your object. Then by having the Lua state, and the name of the global array, you can retrieve the reference to the table and push it onto the Lua stack for that context.
This is sketchy, and I haven't even touched the question of garbage-collecting with this construct.
But in any case this is not going to be the speed racer performance-wise, and looks like a lot of boilerplate C++ code to me. I'd try to reconsider the approach and push some of what you want to do into the Lua domain.
p.s. looks like it is the third question which seems almost a dupe of the previous two ones, here and here are the previous ones. If those were not answered fully, would have been better to edit them/add the bounty to accumulate the answers.