How to check if a member function has been declared in a chai script from C++


#1

I’m trying to check if a class (created inside a .chai script) implements a concrete method.

class ScriptExample1
{
    var m_entityID;

def ScriptExample1() {
    this.m_entityID = 0;
}

def onCreate() {
      print("ScriptExample1 Created with id: " + to_string(this.m_entityID));
}

def onDestroy() {
      print("ScriptExample1 Destroyed with id: " + to_string(this.m_entityID));
}

}

I would like to check from C++ if the ScriptExample1 class implements the method onCreate() (in the example, success) or onUpdate() (in the example, failed) after loading the script file. I would like to check it without the need of instantiate a ScriptExample1 object.

The reason I want this is to avoid calling methods that they do not implement, and call only the existing ones. For example, I can avoid calling onUpdate() in each “frame” if I know that the object doesn’t implement it.

Thank you very much :wink:


#2

Hmm. Well I can think of a few options right now.

First: just try and call it:

// from C++
try {
  chai.eval("obj.onUpdate()");
} catch (const chaiscript::eval_error &) {
  // unable to eval, function didn't exist
}

That’s probably not ideal

The next option would be to ask the engine if the call exists

// from C++
auto exists = chai.eval<bool>("call_exists(onUpdate, obj)");
// exists is now true if the call exists.

The problem with both of these is that they assume you have an object of the type. If you want to just see if the function exists at all you could write a helper. I haven’t tested this, but something like:

def method_exists(Type_Info type, Function func)
{
  if (func.arity() > 0 && func.get_param_types()[0].bare_equal(type)) {
    return true;
  }
  
  var contained = func.get_contained_functions() 

  for(var i = 0; i < contained.size(); ++i) {
    if (method_exists(type, contained[i])) {
      return true
    }
  }
    
  return false;
}

var b = method_exists(MyType, onUpdate);

The problem now that all of these have (except for the very first version, where you just try to call it and hope for the best) is that if no function exists with the name onUpdate at all then you will get an eval_error

So you could amend the last example with:

def method_exists(Type_Info type, String method_name)
{
  // avoid returns and stuff to make this as fast as possible here
  function_exists(method_name)?method_exists(type, get_functions()[method_name]):false;
}

Probably far more info than you wanted, but that’s a few ways to detect if a function exists. Note that these are only testing the type of the first parameter, which is what you asked for, from what I can tell.


How to test for the existence of a var added via add_global
#3

Thank you very much! I will try the third solution. :smile:


#4

Hello, I tried to use your approach. But I didn’t succeed.

I don’t know how to pass a type (Type_Info) as an argument. I tried to pass the class type from my example (ScriptExample1) but after some executions I realized that ScriptExample1 is considered a function (I guess it’s a constructor function). I searched how to retrieve the Type_Info related with ScriptExample1 using a similar approach as get_functions()[method_name] but I didn’t succeed

var typeToCheck = get_type("ScriptExample1");

I’ve seen this method in the docs, but chaiscript raises an exception when I try to execute it, It seems that this method doesn’t exist.

I also tried another approach (I tried to use the constructor function in order to get the Type_Info). Yes, well, maybe I’m inventing too much.

def method_exists(constructorFunction,functionToCheck)
{
      if ((functionToCheck.get_arity() > 0) && functionToCheck.get_param_types()[0].bare_equal(constructorFunction.get_param_types()[0])) {
      print("Method exists");
    return true;
  } else {
      print("Method doesn't exist");
      return false;
  }
}

That way, the check finally worked returning true. The problem is that I created another class ScriptExample2 and it returns that it implements the method onCreate when it doesn’t. Maybe the check is failing because there is already a onCreate method declared by the ScriptExample1 class.

class ScriptExample2
{
    var m_entityID;

def ScriptExample2() {
    this.m_entityID = 0;
}

def onDestroy() {
      print("ScriptExample2 Destroyed with id: " + to_string(this.m_entityID));
}

}

Thank you very much.


#5

It sounds like you didn’t tell ChaiScript the name of your class:

chai.add(user_type<ScriptExample1>(), "ScriptExample1");

…And it seems I failed to put that in the example.

Until C++ adds reflection… it’s what we have to do.

-Jason