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

How to trigger method overridden in js from c? #28

Open
projectitis opened this issue Aug 25, 2021 · 4 comments
Open

How to trigger method overridden in js from c? #28

projectitis opened this issue Aug 25, 2021 · 4 comments

Comments

@projectitis
Copy link

  • Define a class in C++ and expose it to JS
  • Overwrite the method in JS
  • Call the method in C++. How can I make this call the JS method?

Example:

// C++
class ExampleClass {
public:
    void exampleMethod(){
        log( "exampleMethod base" );
    }
}
module.class_<ExampleClass>( "ExampleClass" )
    .fun<&ExampleClass::exampleMethod>( "exampleMethod" );

// JS
class ExtClass extends ExampleClass {
    exampleMethod() {
        console.log("exampleMethod ext");
        super.exampleMethod();
    }
}

I would like this to happen:

// JS
myClass = new ExtClass();

// C++
myClassOpaque->exampleMethod();
// Should log:
//    exampleMethod ext
//    exampleMethod base

I suspect that inside ExampleClass::exampleMethod (and every method where I want this behaviour) I need to check whether the instance has a JS object associated and then manually call exampleMethod on that JS object?

But I'm hoping there is an easier way?

@cykoder
Copy link

cykoder commented Aug 26, 2021

I think the only way to achieve this is to replace myClassOpaque->exampleMethod(); with a quickjs call to invoke exampleMethod using myClassOpaque as an opaque object. C++ doesnt (and cant?) know that exampleMethod was overriden with JS code.

@projectitis
Copy link
Author

Thanks Sam. It's what I was expecting might be the case.

The object myClass is created in javascript. Do you know how I can get the JSValue for myClass from the C++ side? I'd like to make this friendly for the user, so avoiding messy solutions like the user passing it back from javascript to c++ via a method call.

On the C++ side I would like to do something like:

// C++ (psuedo code for brevity)
void myClass::exampleMethod() {
    JSValue jsObj = JS_getObjectForOpaque( this ); // <-- how to do this?
    if (jsObj && JS_HasProperty( jsObj , "exampleMethod" )) {
        JS_EvalThis( jsObj, "this.exampleMethod();" )
    }
}

@cykoder
Copy link

cykoder commented Aug 28, 2021

I'm actually struggling with that same problem just for objects that have been instantiated in JS. EG:

class MyThing extends Thing {
  constructor() {
    super();
  }

  onUpdate() {
     // blah
  }
}

In C++, MyThing::doSomething wants to call the onUpdate method:

  qjs::Value thisVal = getContext()->newValue(this); // i think this is wrong, need to get existing value from opaque
  JSAtom propAtom = JS_NewAtom(ctx, "onUpdate");
  if (JS_HasProperty(ctx, thisVal.v , propAtom )) {
    JSValue funcVal = JS_GetProperty(ctx, thisVal.v, propAtom);
    const char* str = JS_ToCString(ctx, funcVal);
    if (str) {
      LOG_INFO << str;
    }
    JS_FreeCString(ctx, str);

    JS_Call(ctx, funcVal, thisVal.v, 0, NULL);
  } else {
    // doesnt seem to be set, this is what keeps happening
  }

the not set codepath is being taken unless the onUpdate method was defined in c++ too. likely a wrong thisVal - but also not sure how to get jsvalue from my c++ instance. @ftk any ideas?

Previously with dukglue I was able to do dukglue_pcall_method<void>(getContext(), this, "onUpdate", (double)delta); quite easily. Would be great if quickjshpp supported this. If not a pure quickjs way would be appreciated

@ftk
Copy link
Owner

ftk commented Dec 4, 2021

Currently testing this feature in sharedptr branch
fa6c664

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

3 participants