Node.js >= 0.12.* C++ Addon instantiation returning a callback

411 views Asked by At

I have the following functionality working with no issues so long that the call back parameters are string:

void Server::AppUse(const FunctionCallbackInfo<Value>& args) {

    Isolate* isolate = Isolate::GetCurrent();

    HandleScope scope(isolate);

    Local<Function> nextCb = Local<Function>::Cast(args[0]);

    Local<Function> argv[2] = {
        String::NewFromUtf8(isolate, "hello world"),
        String::NewFromUtf8(isolate, "hello again"), 
    };

    nextCb->Call(isolate->GetCurrentContext()->Global(), 2, argv);

}

Implementation in node:

var app = require('./build/Release/middleware');

app.use(function (next, again) {
       console.log(next);
       console.log(again);;
});

This outputs the following implementing node:

$ node ./example.js
hello world
hello again 

However, now I want to add a call back. for example:

void Server::AppUse(const FunctionCallbackInfo<Value>& args) {

    Isolate* isolate = Isolate::GetCurrent();

    HandleScope scope(isolate);

    Local<Function> nextCb = Local<Function>::Cast(args[0]);

    Local<Function> argv[1] = {
        nextCb 
    };

    nextCb->Call(isolate->GetCurrentContext()->Global(), 1, argv);

}

This results in a C++ compilation error:

./src/server.cc:73:63: error: no matching function for call to ‘v8::Function::Call(v8::Local<v8::Object>, int, v8::Local<v8::Function> [1])’
../src/server.cc:73:63: note: candidate is:
In file included from ~/.node-gyp/0.12.4/src/node.h:61:0,
                 from ../src/server.cc:1:
~/.node-gyp/0.12.4/deps/v8/include/v8.h:2557:16: note: v8::Local<v8::Value> v8::Function::Call(v8::Handle<v8::Value>, int, v8::Handle<v8::Value>*)

This basically means that V8::Call only expects an array of values. But what If I wanted to return Function? There is no example in the current addon documentation.

1

There are 1 answers

0
waTeim On

Functions are Values

Casting back and forth really doesn't change the underlying object, rather exposes different member functions. In your case, declare instead

Local<Value> argv[1] = {
    nextCb 
};

Some v8 class Hierarchy info

Yes, argv is an array of Value, however, almost everything (including Function) is - as the following v8 class diagram illustrates; this is taken from thlorenz.com, one of the many v8 documentation sites.

enter image description here

Requiring a Value is nearly the least opinionated a declaration can be since it assumes the least, a Function is an Object and Object is a Value, thus a Function can appear anywhere that expects a Value, going the opposite direction is also allowed using Cast, but the underlying object has to be the actual thing.

Example

For example, the following is legal

void someFunction(const Local<Function> &cb)
{
    Local<Value> v = cb;
    Local<Function> andBack = Local<Function>::Cast(v);
}