Add a member function to a ChaiScript object


#1

Hi! I’m trying to add a function to a ChaiScript object from C++. After reading some examples and docs, I’ve seen that this is easily achieved using add chai.add(chaiscript::fun(&Component::getEntity), "getEntity");. The problem here is that I am adding this function call as a “global” add.

What I would like is to add it into a concrete chaiscript object scope. So then I can call “getEntity” from anywhere inside the member functions.

ScriptComponent.chai

class ScriptComponent
{

def update(dt) {
    // bla bla do some stuff.
    // Ups, I'm a component and I need to check the state of my entity

    var entity = getEntity();

   // do some stuff with entity (a C++ Type)
}

}

As I am implementing an entity-component architecture, where the components are chaiscripts instances, I would like to retrieve the parent entity (a C++ object) from each chai component created. So basically in the C++ function I will need to receive the Boxed_value related with the chaiScript object.

//Somewhere in c++
Entity Component::getEntity(chaisscript::Boxed_Value fromComponent) {
   // Using the Boxed_Value parameter I would check the entity this component belongs to
   // ...
   return entity;
}

Do you have any clue, of how can I add a “binding” for each instance. Take in account that I will be using many different chai components, and each of them should be able to call getEntity().

Thank you very much, sorry, I tried to explain my approach the best I could :smile:


#2

Maybe I’m confused or over simplifying it, but wouldn’t just calling:

def update(dt) {
    // bla bla do some stuff.
    // Ups, I'm a component and I need to check the state of my entity

    // pass in 'this'
    var entity = getEntity(this);
   // do some stuff with entity (a C++ Type)
}

Or even if you prefer the dot syntax:

def update(dt) {
    // bla bla do some stuff.
    // Ups, I'm a component and I need to check the state of my entity

    // pass in 'this'

    var entity = this.getEntity();
    // do some stuff with entity (a C++ Type)
}

That is how it would be called if it were an instance method anyhow, and would work with the code you have set up currently.

-Jason


#3

Well, that’s the solution I thought at first glance. But in this case, if I am right, we are using a “global method” passing the object as the first parameter. Sorry if it’s an obvious question but, is there any difference in the C++ function declaration between the first and the second option that you answered? Will I receive the Boxed_value object as the first parameters with both calls? I understand then, this is the proper way to add member functions to chaiscript :wink:


//Somewhere in c++
Entity Component::getEntity(chaisscript::Boxed_Value fromComponent) {
   // Using the Boxed_Value parameter I would check the entity this component belongs to
   // ...
   return entity;
}

Thank you very much in advance.


#4

There is no difference between the first and second methods. ChaiScript essentially does a translation internally of obj.fun() to fun(obj). There are a few minor internal differences - we are actually able to make some different assumptions so the obj.fun() syntax is slightly faster to execute.

You can take advantage of this to do things like:

def string::sizeTimes2() {
  this.size() * 2 // 'return' keyword is not required on last statement
}

"bob".sizeTimes2(); // returns 6

And this is equivalent to:

def sizeTimes2(string s) {
  s.size() * 2;
}

"bob".sizeTimes2(); // returns 6

And this is the same from the C++ side. You can add methods:

class MyClass 
{
  public:
    void doSomething();
}

chai.add(fun(MyClass::doSomething), "doSomething");

Because of the way C++ works, it’s actually required that I convert this at compile time from the function

void MyClass::*f()

Into a function like:

void f(MyClass *)

I hope that makes sense. The two types of function calls are interchangeable both when registering them from C++ land and when calling them / defining them in ChaiScript land.


#5

Thank you very much, nice explanation btw!