matusnovak / wrenbind17

A header only library for binding C++17 classes and functions to Wren, an embeddable programming language
https://matusnovak.github.io/wrenbind17
MIT License
65 stars 10 forks source link

Non-copyable types cannot have a constructor #5

Closed germandiagogomez closed 3 years ago

germandiagogomez commented 3 years ago

As the title says, constructors cannot use non-copyable types. I think this could be workarounded in some way. This means that types with a mutex, for example, cannot be returned from a klass.ctor<MyType>.

I think this derives from the rules to handle parameter passing. I wonder if constructors could be a special case to return stuff avoiding copies:

https://matusnovak.github.io/wrenbind17/tutorial/custom_types/#62-passing-values-into-wren

matusnovak commented 3 years ago

Hi @germandiagogomez I am currently busy but I will look at this soon.

matusnovak commented 3 years ago

Hi @germandiagogomez

That's a very tricky thing to do since Wren is garbage collected and it would not know that the instance is no longer valid.

Theoretically, it would be possible to take the stored pointer in shared_ptr, move it into the constructor, then mark that foregin class instance in Wren as empty. The problem is that there is no such public interface in Wren to do that.

One way I can think of, a little hack, is to create a static method in your class that receives the non-copyable type as a shared_ptr. The static method would move the instance into the constructor, invaliding the stored instance in the shared_ptr. Proposed solution below.

However, it would cause undefined behavior if you want to use that someClass variable somewhere else. It would be nice if Wren had API that would make this variable into null.

In any case, I really do not wish to create difference on parameter passing logic between functions, constructors, or on return.

class MyType { // non copyable type
};

class SomeClass {
public:
    SomeClass(MyType myType) myType(std::move(myType)) { ... }

    static SomeClass from(std::shared_ptr<MyType> myType) {
        return SomeClass(std::move(*myType));
    }
};

int main() {
    ...
    auto& cls = m.klass<SomeClass>("SomeClass");
    // no ctor
    cls.funcStatic<&SomeClass::from>("from");
};

And then in Wren:

class Main {
    static main() {
        var myType = MyType.new()
        var someClass = SomeClass.from(myType) 
    }
}
germandiagogomez commented 3 years ago

Hello @matusnovak

Your static trick is what I ended up doing even before you documented it, it looked like the obvious way to me too. Not sure how tricky making non-copyable types in constructors is, but I am sure ChaiScript can do it. I do not know the internal details, though, so I cannot talk for what I do not know lol.

Thanks for your support and prompt reply.