Creating script objects from C++


#1

I have a class defined in my script file. I pass the class name to my C++ code, which calls its constructor and saves the returned Boxed_Value for later use (like calling methods of that object). What I want next is to return this object back to script to make it available there. The problem is that, according to my tests, I get two different objects.

C++:

ChaiScript engine(Std_Lib::library());
Boxed_Value obj;

// ...

Boxed_Value& create(const std::string& className)
{
    obj = engine.eval<Boxed_Value>(className + "()");
    return obj;
}

void call()
{
    auto func = engine.eval<std::function<void(Boxed_Value&)>>("func");
    func(obj);
}

// ...

engine.add(fun(create), "create");
engine.add(fun(call), "call");

Script:

class Test
{
    var id;

    def Test()
    {
        this.id = 10;
    }

    def func()
    {
        print(this.id);
    }
}

var t = create("Test");
t.id = 100500;
t.func();
call();

I conclude that I have different objects because the output is 100500, then 10. How can I make t point to the same object?


#2

ChaiScript is doing a deep clone of the value returned from your create() function.

We try to not unnecessarily copy objects, but do when necessary to maintain consistency of behavior with C++.

To prevent cloning, do a reference assignment:

var t := create("Test");

or if you prefer:

var &t = create("Test");

Or if you really want to model c++:

auto &t = create("Test");

The complete example I compiled for anyone else who wants to play with this:

#include "chaiscript/chaiscript.hpp"
#include "chaiscript/chaiscript_stdlib.hpp"

chaiscript::ChaiScript engine(chaiscript::Std_Lib::library());
chaiscript::Boxed_Value obj;


chaiscript::Boxed_Value& create(const std::string& className)
{
  obj = engine.eval(className + "()");
  return obj;
}

void call()
{
  auto func = engine.eval<std::function<void(chaiscript::Boxed_Value&)>>("func");
  func(obj);
}


int main()
{
  engine.add(chaiscript::fun(create), "create");
  engine.add(chaiscript::fun(call), "call");

  engine.eval(R"(
      class Test
      {
        var id;

        def Test()
        {
          this.id = 10;
        }

        def func()
        {
          print(this.id);
        }
      }

      var &t = create("Test");
      t.id = 100500;
      t.func();
      call();
      )");
}

#3

Would it make any difference if I returned Boxed_Value instead of a reference from the create function?


#4

I think for internal consistency I have to treat both the same. You’re welcome to try it.

I think reference assignment is your best bet anyhow, then you are being clear that you don’t want a copy, just as you would similarly do in C++