Bind C++ properties to chai script, how?


#1

I want to register a property to chai script

struct foo
{
void set_value(int v) { value = v; }
int get_value() { return value; }
private:
int value;
};

How do I bind this member functions as property to chai?

var obj = Foo()
obj.value = 12

when I set value, internally the set_value function will be called.


#2

@lefticus
So I guess it is not possible?


#3

you can just bind the two helpers, or bind the member directly.
if you really want it exactly like above you could create struct that is convertible to and from int (or templated type). bind its operator=() to helper. then use that as the member.


#4

@ninnghazad
Please show me the binding code so that this example works like provided.


#5

I think it wasn’t clear what i was trying to say: what you want to do is not worth the effort.
just bind value directly or bind the getter/setter functions and use those.
having value magically call get/set in script creates more problems than it seems to solve on the first glance. the pro is just syntactic sugar, the cons are many. what is supposed to happen when users do e.g:
obj.value *= obj.value / (obj.value + 2);
?
For the sake of it look at this:

#include <iostream>
#include <chaiscript/chaiscript.hpp>

template<typename T> struct Value {
        T value;
        Value():value(static_cast<T>(0)) {}
        Value(T value):value(value) {
                std::cout << "value constructor" << std::endl;
        }
        operator T&() {
                std::cout << "reference getter" << std::endl;
                return value;
        }
        operator T() const {
                std::cout << "value getter" << std::endl;
                return value;
        }
        template<typename U> friend std::ostream& operator<<(std::ostream &os, const Value<U> &v);

};
template<typename T> std::ostream& operator<<(std::ostream &os, const Value<T> &v) {
        return os << "Value(" << v.value << ")";
}

struct Struct {
        Value<int> value;

        int simpleValue = 0;
        void setValue(int v){
                simpleValue = v;
        }
        int getValue() {
                return int{simpleValue};
        }
};

using namespace chaiscript;
int main() {
        ChaiScript chai;

        chai.add(user_type<Value<int>>(), "IntValue");
        chai.add(constructor<Value<int>()>(), "IntValue");
        chai.add(constructor<Value<int>(const Value<int>&)>(), "IntValue");
        chai.add(constructor<Value<int>(int)>(), "IntValue");
        chai.add(chaiscript::fun([](const Value<int> & i){
                std::ostringstream os;
                os << i;    
                return os.str();
        }),"to_string");    
        chai.add(chaiscript::fun([](Value<int> & v,const int i){
                std::cout << "custom operator=" << std::endl;
                v.value = i;
        }),"=");
        // ... lots more custom operators for this to work as expected in all cases ...


        chai.add(user_type<Struct>(), "Struct");
        chai.add(constructor<Struct()>(), "Struct");
        chai.add(constructor<Struct(const Struct&)>(), "Struct");

        // Weird wrapped value
        chai.add(fun(&Struct::value), "value");

        // Direct value
        chai.add(fun(&Struct::simpleValue), "simpleValue");

        // Getter/Setter
        chai.add(fun(&Struct::getValue), "getValue");
        chai.add(fun(&Struct::setValue), "setValue");

        chai.eval(R"(
                // A weird way
                var s = Struct();
                s.value = 1;
                puts("value: "+s.value.to_string()+"\n");

                // A simple way (recommended)
                s.simpleValue = 2;
                puts("simpleValue(direct): "+s.simpleValue.to_string()+"\n");

                // A simple way with getter/setter (recommended)
                s.setValue(3);
                puts("simpleValue(get/set): "+s.getValue().to_string()+"\n");
        )");
        return 0;
}

See how simple direct access or just binding get/set is? And see how complicated shoehorning value to get/set is? While technically it works as requested on the script side, you’d have to write a lot more like that for it to behave like an int in all other possible cases.

So - just bind the value or get/set. Not only is it simple and clean - it also behaves as a user would expect it to.


#6

Thanks for looking into it.
However, I wounder why there is not direct support for this in chaiscript. Maybe the main developer can say something to this. IMHO, it should be pretty easy to implement support for this.
@lefticus
Can you say something to this?