2

I am sure some of you might run into this problem. I have a userdata object called matrix written in C++ with usual ways of operator overloading, such as.

CMatrix<T>& operator=(const CMatrix<T>& b);
CMatrix<T>& operator=(const T& rhs);

In C++ when I create two matrices say A and B and make A=B then A and B can be used as two independent objects. However, in Lua when I write A=B and change any property of B, then A changes as well.

It is apparent and also from the Lua manual it is said that Lua makes the assignment of userdata by reference which explains the above mentioned behaviour. However, how can I make A=B to pass by value so that when B changes A is not affected.

As a matter of fact, I want to make the assignment A=B pass by reference which is indeed very fast and which Matlab does, but when I set a property of B for the first time, I want B to be created independently which is practiced my Matlab as I could have tracked from memory usage of Matlab.

If this is possible, is it done inside C++ or somewhere in the lua wrapper codes? Any example code would be great.

EDIT 1: Here is my idea, I am not sure if it will work at all or if so fast enough

typedef struct luaelement
{
   int type;
   std::string name;
   void* addr; //newly added field
   bool isRef;  //newly added
} luaelement;

glbLuaElementSet=new set<luaelement,comparenocaseforluaelement>();

int l_newindex(lua_State* L)
{
    luaelement element;
    const char* key=lua_tostring(L,-2);
    string str=key;
    element.name=key;
    element.type=lua_type(L,-1);
    //How can I get the address, maybe a metamethod named address
    glbLuaElementSet->insert(element); 
    lua_rawset(L,1);
}

void l_registermetamethod(lua_State* L)
{
    lua_getglobal(L,"_G");
    lua_createtable(L, 0, 1);
    lua_pushcfunction(L, l_newindex);
    lua_setfield(L, -2, "__newindex");
    lua_setmetatable(L, -2);
}

Now with the glbLuaElementSet variable and l_newindex metamethod I can track all the variables inserted at global _G table. I was planning to implement and see if any reference to already existing userdata variable is in place by checking the void* address. I am not sure if this will really work and if it is worth the effort in terms of performance.

4
  • Your last part is a strictly C++ question; what you're talking about is called "copy-on-write" semantics. Unless your matrix objects are big, it's usually a terrible idea for a value type. Sure, it sounds fast. But with modern move semantics and copy elision, you'll find yourself not doing very much copying of objects. It also makes your objects very non-thread-safe, or requires you to lock mutexes to access them. Commented Feb 5, 2016 at 2:05
  • 2
    "how can I make A=B to pass by value so that when B changes A is not affected." - this is like asking "How can I make the MyClass c = new MyClass(); work in C++ like it does in Java?" - even if you can (and I think you can't), it's not a good idea. Commented Feb 5, 2016 at 2:09
  • I would just had a method to the matrix for cloning it. Commented Feb 5, 2016 at 9:46
  • @warspyking: That is exactly what I am planning to do after reading all the comments. Commented Feb 9, 2016 at 1:04

1 Answer 1

4

However, how can I make A=B to pass by value so that when B changes A is not affected.

You can't.

Remember: Lua is dynamically typed. So while A and B happen to store your matrix type right now, it's perfectly fine to later go A = 1. Now, A stores an integer.

C++ and Lua are very different languages. In C++, variables are either objects or references to objects (pointers are objects of pointer type). Each variable will only ever hold the object that it starts with. The value stored in that object can be changed, but the object itself exists and has a lifetime defined by the lifetime of the variable in question.

In Lua, a variable is just a box that objects can be stored in. That box has no relationship to the object that it currently happens to store; any box can hold any object. And at any time, you can swap what's in that box with the object from any other box.

You cannot interfere in the copying of one variable into another (generally. You could do metatable gymnastics, but that would only apply to members of that table. Local variables would never be affected). This is simply how Lua works as a language. C++ variables are objects; Lua variables are storage boxes. It's best to accept that you can't write C++-style code in Lua, and instead focus on writing Lua-style code in Lua.

So if you want to create a copy of an object, you have to create a copy of that object explicitly.


Here is my idea, I am not sure if it will work at all or if so fast enough

It will not work for several reasons.

First, you're applying a metatable to the global table itself, which is typically... rude.

Second, even if your code worked, it wouldn't work for something as simple as this:

globalVar = {}  --Perfectly legal to set a table inside the global table.
globalVar.value = A
globalVar.value = B  --Will not alert your copying code.

The __newindex metamethod is not recursive. It can't walk up and down the hierarchy of tables. So a table stored within the global table can still have its members changed.

Stop trying to make Lua into something it isn't. Work with the language you have, not the language you want.

Sign up to request clarification or add additional context in comments.

2 Comments

Tables and functions and userdatas in Lua are referenced by a variable. Numbers, strings, bools, and nil however are held by a variable.
@NicolBolas: Thanks for your comments, especially the last bit "you have, not the language you want" :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.