Thank you Chad for this detailed answer. This is exactly what I needed.

I found the exact same workaround as yours, but I don't like it because it 
requires to write some JavaScript code to call the callback. I've also 
thought about the second approach (generated JavaScript functions calling 
back C++ functions mapped with ids) but it sounds quite hard to get right 
and definitely requires to learn the intrinsics of embind. I think I see 
the global picture but I'm still lost in the details. What would be the 
process to implement it?

   - create a global store like std::map<int, Function> where Function is a 
   generic std::function with type information erased
   - create a dispatcher method which takes an id as input and variadic 
   parameters and calls the C++ Function (how to deal with type information 
   here?)
   - register a new wire type for each std::function<T> signature used
   - put the function in the map associated with its unique id
   - define a new function named _embind_callback_<id> using 
craftInvokerFunction 
   or similar which calls the C++ dispatcher
   - use _embind_callback_<id> wherever a function is passed as argument

Am I missing something? By the way, this approach doesn't solve the memory 
leak and I can't think of a way to fix it since there is no way to specify 
a destructor for the allocated C++ function object.

On Tuesday, July 1, 2014 2:36:56 AM UTC+2, Chad Austin wrote:
>
> Hi Warren,
>
> embind and emval don't currently support this functionality.  That doesn't 
> mean it's impossible, just that we haven't thought through how it work.  
> There are two main challenges.  Let's discuss them and see what we can do 
> here.
>
> Your example of passing a lambda as an argument to to 
> emscripten::val::call() is great because it looks nice and simple but it 
> hides its unclear lifetime semantics.  That is, a C++ lambda is just sugar 
> for a class with a call operator.  In your example, that class is allocated 
> on the stack and passed by either value or rvalue reference to the call<> 
> function.  Since the lambda's type has never been registered with embind, 
> it doesn't know how to convert it into a JavaScript object.
>
> Even if embind did know how to convert the lambda into a JavaScript 
> object, that JavaScript would have a pointer to a C++ heap object, which it 
> would then need to deallocate at some point.  How and when would it 
> deallocate it?  JavaScript just assumes everything's garbage collected, so 
> it would never notify Emscripten that it needs to free some heap memory.  
> Thus, every use of this API would leak memory.
>
> What we've done here at IMVU is have the C++ bind an interface with 
> callback methods on it, and then have a JavaScript implementation of that 
> interface that sets up the callbacks.  Something like:
>
> struct Callbacks {
>     void invoke() {
>         callback();
>     }
>
>     std::function<void()> callback;
> };
>
> class_<Callbacks>("Callbacks")
>     .function("invoke", &Callbacks::invoke);
>     ;
>
> Then you can have a bit of JavaScript that, when given a Callbacks object, 
> will do something like:
>
> function registerCallback(cb) {
>     object.on('connect', function() {
>         cb.invoke();
>         // when do you deallocate the callback object? that's up to your 
> application
>     });
> }
>
> Is there a nicer approach?  Perhaps!
>
> Maybe we could do something where we can generate JS function objects 
> associated with integer handles and then C++ could map each integer handle 
> back to the appropriate std::function...
>
> Do you have any ideas?
>
> On Sat, Jun 28, 2014 at 4:03 PM, Warren Seine <[email protected] 
> <javascript:>> wrote:
>
>> I'm using embind to wrap a JS library in C++. The library uses callbacks 
>> such as:
>>>
>>> object.on('connect', function() {
>>>   console.log('connected');
>>> });
>>
>> How can I use a C++ function as callback?
>>
>> Ideally, I'd like to do something like:
>>
>>> val object = val::global("object");
>>> object.call<void>("on", std::string("connect"), []() {
>>>   std::cout << "connected" << std::endl;
>>> });
>>
>> which, unfortunately, throws "Uncaught BindingError: parameter 2 has 
>> unknown type" with a mangled lambda type name.
>>
>> Chad recently posted something related to C++ callbacks 
>> <http://chadaustin.me/2014/06/emscripten-callbacks-and-c11-lambdas/> but 
>> doesn't talk about this specific issue. If that's unsupported, what would 
>> embind need to support C++ callbacks?
>>
>> Also, what's the workaround?
>>
>>
> -- 
> Chad Austin
> Technical Director, IMVU
> http://engineering.imvu.com <http://www.imvu.com/members/Chad/>
> http://chadaustin.me
>  

-- 
You received this message because you are subscribed to the Google Groups 
"emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to