pmed / v8pp

Bind C++ functions and classes into V8 JavaScript engine
http://pmed.github.io/v8pp/
Other
901 stars 121 forks source link

extended classes from native classes are missing newly defined functions #180

Closed MangelSpec closed 1 year ago

MangelSpec commented 2 years ago

Hello, if exposing a native class and create a derived script one from it, newly created functions are undefined for some reason. Properties, constructors and static methods work however. I created a minimal example to see what I mean:

#include <iostream>

#include <v8.h>
#include <libplatform/libplatform.h>

#include <v8pp/context.hpp>
#include <v8pp/class.hpp>

class Foo {
public:
    Foo() = default;
};

class Log
{
public:
    auto log(const std::string& log) -> void { std::cout << log << std::endl; }
};

int main()
{
    v8::V8::InitializeICU();

    auto platform = v8::platform::NewDefaultPlatform();
    v8::V8::InitializePlatform(platform.get());
    v8::V8::Initialize();

    v8pp::context context;
    auto* isolate = context.isolate();
    v8::HandleScope scope(isolate);
    v8::Context::Scope context_scope(context.impl());

    v8pp::class_<Log> logclass(isolate);
    logclass.function("log", &Log::log);
    context.class_("Foo", logclass);

    v8pp::class_<Foo> v8ppclass(isolate);
    v8ppclass.ctor<>();
    context.class_("Foo", v8ppclass);

    auto func = v8::FunctionTemplate::New(isolate);
    func->SetClassName(v8::String::NewFromUtf8(isolate, "Foo2").ToLocalChecked());
    context.value("Foo2", func->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()); 

    context.value("console", v8pp::class_<Log>::create_object(isolate));

    const v8::TryCatch try_catch(isolate);
    context.run_file("index.js");
    if (try_catch.HasCaught()) {
        std::cout << v8pp::from_v8<std::string>(isolate, try_catch.Exception()->ToString(isolate->GetCurrentContext()).ToLocalChecked());
    }

    getchar();
    return 0;
}

the loaded index.ts which gets translated to index.js

class Test extends Foo {
  public new1(): void { console.log("new1"); }
  static new2(): void { console.log("new2"); }
  public new3: number = 0;
  public new4 = () => console.log("new4");
}

class Test2 extends Foo2 {
  public new1(): void { console.log("new1"); }
  static new2(): void { console.log("new2"); }
  public new3: number = 0;
  public new4 = () => console.log("new4");
}

let test = new Test();
console.log(`${Test.name}, ${typeof test}, ${typeof test.new1}, ${typeof Test.new2}, ${typeof test.new3}, ${typeof test.new4}`);

let test2 = new Test2();
console.log(`${Test2.name}, ${typeof test2}, ${typeof test2.new1}, ${typeof Test2.new2}, ${typeof test2.new3}, ${typeof test.new4}`);

the index.js which gets loaded

(()=>{"use strict";class Test extends Foo{constructor(){super(...arguments),this.new3=0,this.new4=()=>console.log("new4")}new1(){console.log("new1")}static new2(){console.log("new2")}}class Test2 extends Foo2{constructor(){super(...arguments),this.new3=0,this.new4=()=>console.log("new4")}new1(){console.log("new1")}static new2(){console.log("new2")}}let e=new Test;console.log(`${Test.name}, ${typeof e}, ${typeof e.new1}, ${typeof Test.new2}, ${typeof e.new3}, ${typeof e.new4}`);let o=new Test2;console.log(`${Test2.name}, ${typeof o}, ${typeof o.new1}, ${typeof Test2.new2}, ${typeof o.new3}, ${typeof e.new4}`)})();

the output result of binding the class with v8pp vs v8

Test, object, undefined, function, number, function
Test2, object, function, function, number, function

So as you can see, the test.new1 function is somehow missing and undefined from the derived class. I tried to find out what's causing this, but I didn't really see any issue, except that there are 2 function templates used for binding classes in v8pp with func_ and jsfunc. Maybe you can explain why two function templates are used and useful for v8pp?

legacy3 commented 2 years ago

Me, too, encountered this issue.

legacy3 commented 1 year ago

any news on this?

pmed commented 1 year ago

Hi,

I suspect this issues in related with class inheritance. At the time of the library creation there was no such such ability in pre-ES6 JavaScript, so v8pp uses prototype-based constructor functions.

Sorry, I have no spare time to dig into the issue details, maybe someone could find a way to fix this.