Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function & constructor overloading #125

Open
ayles opened this issue Aug 30, 2019 · 6 comments
Open

Function & constructor overloading #125

ayles opened this issue Aug 30, 2019 · 6 comments

Comments

@ayles
Copy link

ayles commented Aug 30, 2019

I'm also intrested in possibility of setting functions and constructors like:

// constructors
.ctor<double>().ctor<double, double>()
// functions
.function<void, double>(&X::add).function<void, double, double>(&X::add)
// or solve disambiguation with static_cast hint
.function(static_cast<void (X::*)(double)>(&X::add))

Then best match will be selected.
As far as I understand adding two or more functions is not as difficult as selecting wich one to use, cause here should be some rules like:

First, try find handler with same argument count.
Second, try find exact argument type match.
If there is no such handler, ...?
In any other case select handler with (const FunctionCallbackInfo &) signature if available.

So, is it possible and do you have any thoughts about it?

@ayles
Copy link
Author

ayles commented Aug 31, 2019

Tried to implement some kind of function selecting behaviour.
Gist.
So we're checking if arguments match for each passed function sequentially. On first match we're calling and just exiting with true returned, or if there was no match false is returned.
I'm quite unfamiliar with templates but I think this idea is fine, so check it please...

@pmed
Copy link
Owner

pmed commented Sep 1, 2019

Hi,

yes, there was such a request earlier in #41. The issue as I see, is the overloaded functions dispatching can be resolved only at run-time, since an overloaded C++ wrapped function can be invoked in JavaScript with any argument list.

So a generic f(v8::FunctionCallbackInfo<v8::Value> const& args) would lookup a suitable C++ function in a registry of overloads.

Current class_ implementation sets a wrapped function value in the class prototype template. Unfortunately, v8::Template has no API to get previously set value, so for overloaded functions v8pp::class_ instance would have to track the function names, in order to replace overloaded ones with a generic dispatching version. And this tracking is required only on the class binding step.

@ayles
Copy link
Author

ayles commented Sep 1, 2019

Hmm, I tried to implement simple function wrapping this morning.
And it works. Use looks like this:

void f(int a) {
    std::cerr << "One int arg: " << a << std::endl;
}

void f(int a, int b) {
    std::cerr << "Two int args: " << a << " " << b << std::endl;
}

void f(std::string s) {
    std::cerr << "String arg: " << s << std::endl;
}

...

// binding (static_cast here used as hint to compiler, functions with names `f1` `f2` `f3` can be bound just by passing name)
context->Global()->Set(context, v8_str("test"), 
    v8b::wrap_function(isolate, 
        static_cast<void(*)(int, int)>(f), 
        static_cast<void(*)(int)>(f), 
        static_cast<void(*)(std::string)>(f)
    )->GetFunction(context).ToLocalChecked()
);

...

// usage (in js)
test(1); 
test(1, 3); 
test("str");

Output will be

One int arg: 1
Two int args: 1 3
String arg: str

How it works:
On function template creation I'm passing v8::External with array of void * pointers to all passed functions.
Then I'm binding handler that is result of calling template function get_handler that accepts all passed functions along with their signatures in templates. get_handler builds handler that sequentially will compare args passed from js and functions signatures:

arguments_traits<typename function_traits<F>::arguments>::is_match(info)

And if there is match, it gets function pointer with current index from info.Data(), casts it and calls with converted arguments.

So this approach is half-runtime half-compiletime (and it relies on template instantiation recursion =), and for any functions sequence passed will be generated new handler, but it is quite fast and requires no runtime type checks...

I hope you get the idea, because my English is very bad.

Now I see that it will be hard to just add this functionality to v8pp, it is easier just to rewrite it from scratch...

@pmed
Copy link
Owner

pmed commented Sep 1, 2019

Thanks for sharing the idea!

I haven't thought before to use an array of functions with the same name for single wrap_function() call.

@ayles
Copy link
Author

ayles commented Sep 5, 2019

Hi again)
Started implementing ideas inspired by your lib here: https://github.com/ayles/v8bind
I'll later add link to v8pp in README.
Class member variables binding and multiple constructors binding works fine,
will add function overloads binding later.

@pmed
Copy link
Owner

pmed commented Sep 6, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants