ThePhD / sol2

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
http://sol2.rtfd.io/
MIT License
4.06k stars 492 forks source link

Is it possible to have out params / replace type and data referenced by sol::object? #1591

Open shohnwal opened 3 months ago

shohnwal commented 3 months ago

Some programming languages offer the possibility of out-parameters, aka where the user can pass in arguments as reference to a function, inside the function the value gets modified via reference and once the function returns the value stays modified.

I can modify sol::objects content if they are already of the correct type, as I can just get an already correctly typed reference to their underlying value. however, what if the passed-in sol::object is of a different type, is it possible to replace the referred-to Lua value with a new object?

local u = MyUserType()
local n = nil
local v = 42
DoSomething(u)
DoSomething(n)
DoSomething(v)
--all three values should now be of type MyUserType
u:UserTypeFunc()
n:UserTypeFunc()
v:UserTypeFunc()
void DoSomething(sol::variadic_args args)
{
  sol::object obj = args[0];
  if(obj.is<MyUserType>())
  {
    MyUserType& data = obj.as<MyUserType&>();
    //modifyl MyUserType data
    //...
    //data obj refers to is now modified, as expected with an out-parameter, no issues here
  }
  else
  {
    // How to replace the type and data of whatever obj refers to with a new instance of MyUsertype?
    //for example, what if obj is referring to a number or nil, is it possible to replace that with a new 
    //instance of MyUserType? I can't just do 
    obj = sol::make_object<MyUserType>(...)
    //as it would only change what the obj in this scope would refer to, not what the input parameter 
    //in args or the variable in Lua refers to
  }
}

I know I can always use sol::variadic_results to return multiple values and do

local v = 42
v = DoSomething(v)
-- v is now userdata
sol::variadic_results DoSomething(sol::variadic_args args)
{
  sol::variadic_results results{};
  sol::object obj = args[0];
  if(obj.is<MyUserType>())
  {
    // do stuff with userdata and return it
    results.push_back(obj);
  }
  else
  {
     sol::object newUserData = ...
     results.push_back(newUserData);
  }
  return results;
}

but I was wondering whether it's possible to mimic out-parameters somehow, as it would be more consistent with what some people are used to with other languages.

By the way, thank you for this fantastic work. I have been using sol2 for years and I am very happy with it!

Rochet2 commented 3 months ago

What you want to do in your example may be possible, but not exactly supported by lua. You would need to use the debug library to replace the value of local variables. See https://www.lua.org/manual/5.1/manual.html#pdf-debug.setlocal

For some alternative approaches see https://github.com/ThePhD/sol2/issues/1323#issuecomment-1060051422

shohnwal commented 3 months ago

Oh, dumb me, I totally forgot that primitives get passed by value. Never mind then, I'll just use the variadic_results approach then.

Thank you for the links! :)