In lua, is there a way to bind the upvalue value to the userdata value instead of a function?

The following example creates a userdatatype value MyType, and the table is created using the metafunction __tostringthat invokes LI_MyType__tostring. Code creates a LOP OOP based on closure. My problem with the provided example looks as if there is only one way to associate userdatawith a method call through upvalues. This in itself is not a problem if I do not want to use the same metatet between instances.

In an ideal world - and what do I hope to find in this question - is there a way to associate an upvalue value with a value (for example userdata) without associating it with a function call through an upvalue? I hope there is a trick that will allow me to continue to use loo OOP based on closure and use the same metatet for different instances. I am not an optimist, but I decided that I would ask to see if anyone has a suggestion or an unobvious trick.

using FuncArray = std::vector<const ::luaL_Reg>;
static const FuncArray funcs = {
  { "__tostring", LI_MyType__tostring },
};

int LC_MyType_newInstance(lua_State* L) {
  auto userdata = static_cast<MyType*>(lua_newuserdata(L, sizeof(MyType)));
  new(userdata) MyType();

  // Create the metatable
  lua_createtable(L, 0, funcs.size());     // |userdata|table|
  lua_pushvalue(L, -2);                    // |userdata|table|userdata|
  luaL_setfuncs(L, funcs.data(), 1);       // |userdata|table|
  lua_setmetatable(L, -2);                 // |userdata|
  return 1;
}

int LI_MyType__tostring(lua_State* L) {
  // NOTE: Blindly assume that upvalue 1 is my userdata
  const auto n = lua_upvalueindex(1);
  lua_pushvalue(L, n);                     // |userdata|
  auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
  lua_pushstring(L, myTypeInst->str());    // |userdata|string|
  return 1;                                // |userdata|string|
}

I hope there is a way to accomplish something like this (this is pseudo code!):

// Assume that arg 1 is userdata
int LI_MyType__tostring(lua_State* L) {
  const int stackPosition = -1;
  const int upvalueIndex = 1;
  const auto n = lua_get_USERDATA_upvalue(L, stackPosition, upvalueIndex);
  lua_pushvalue(L, n);                     // |userdata|
  auto myTypeInst = static_cast<MyType*>(lua_touserdata(L, -1));
  lua_pushstring(L, myTypeInst->str());    // |userdata|string|
  return 1;                                // |userdata|string|
}

I know this looks like everything will be for the β€œnormal” metatable OOP style, but I want things to close and not introduce a colon syntax.

: userdata ? lua , , , -, .


UPDATE (2013-10-10): @lhf lua_setuservalue() lua_getuservalue() :

  • , luaL_newmetatable(). metatable userdata, .
  • userdata (lua_newuserdata()).
  • metatable userdata (lua_setmetatable()).
  • / upvalue, userdata.
  • lua_setuservalue() userdata / .
  • (, __index), userdata uservalue.

:

  • upvalues ​​
  • upvalues ​​ .

- / , . , obj.myMethod() obj function myMethod() - :, , :, - ( upvalue).

+4
2
+1

, .

  • object.method() , , .
  • , ( ).

1 , . (LuaL_checkudata)

tostring, , . , , , , .

0

All Articles