Skip to content
New issue

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

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

Already on GitHub? # to your account

[cppia] Cant seem to get host to call extern super functions #1150

Closed
ianharrigan opened this issue Sep 4, 2024 · 7 comments · Fixed by HaxeFoundation/haxe#11773
Closed

Comments

@ianharrigan
Copy link

ianharrigan commented Sep 4, 2024

So Ive reduced my problem scope to the following:

In the cppia host:

class FakeButton extends FakeInteractiveComponent {
    public override function someFunction() {
        super.someFunction();
        trace(">>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeButton");
    }
}

class FakeInteractiveComponent extends FakeComponent {
    public override function someFunction() {
        super.someFunction();
        trace(">>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeInteractiveComponent");
    }
}

class FakeComponent extends FakeComponentBase {
    public override function someFunction() {
        super.someFunction();
        trace(">>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponent");
    }
}

class FakeComponentBase {
    public function new() {
    }

    public function someFunction() {
        trace(">>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponentBase");
    }
}

As expected if you create an instance of this in the host (new FakeButton()) and call the someFunction() then things trace as you would imagine:

src/fake/FakeComponentBase.hx:8: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponentBase
src/fake/FakeComponent.hx:6: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponent
src/fake/FakeInteractiveComponent.hx:6: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeInteractiveComponent
src/fake/FakeButton.hx:6: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeButton

All fine, however, in the script file, i have a set of externs for these classes, as well as a class that extends one of these externs:

@:expose("MyFakeButton")
class MyFakeButton extends FakeButton {
    public override function someFunction() {
        super.someFunction();
        trace(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MyFakeButton.someFunction");
    }
}

extern class FakeButton extends FakeInteractiveComponent {
    public function someFunction():Void;
}

extern class FakeInteractiveComponent extends FakeComponent {
    public function someFunction():Void;
}

extern class FakeComponent extends FakeComponentBase {
    public function someFunction():Void;
}

extern class FakeComponentBase {
    public function someFunction():Void;
}

When i load this script into the host, create an instance of the FakeButton (via cpp.cppia.Module.resolveClass) and call someFunction i, weirdly, get the following:

src/fake/FakeComponentBase.hx:8: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponentBase
src/MyFakeButton.hx:9: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MyFakeButton.someFunction

Its like its skipped the rest of the class hierarchy or something, ive tried various things but can never seem to get it to call, for example, FakeComponent.someFunction

Any thoughts, is there something ive doing incredibly wrong here?

Note1: i tried adding override to the extern functions, same thing

Note2: a similar thing is perfectly fine with js (obviously not using cppia), but dynamically loading a .js file and creating class instances

Note3: i thought it might be somewhat related to: #423 - albiet not using externs, etc - but my understanding is that issue was fixed anyway

@ianharrigan
Copy link
Author

ianharrigan commented Sep 4, 2024

If i do the following (in the host):

                    var superClass = Type.getSuperClass(Type.getClass(button));
                    while (superClass != null) {
                        trace(Type.getClassName(superClass));
                        superClass = Type.getSuperClass(superClass);
                    }

(button being the class instance that is created from the cppia script)
Then everything seems normal:

src/MainView.hx:83: fake.FakeButton
src/MainView.hx:83: fake.FakeInteractiveComponent
src/MainView.hx:83: fake.FakeComponent
src/MainView.hx:83: fake.FakeComponentBase

/shrug

@hughsando
Copy link
Member

This stuff can get a little confusing.
Is the problem basically in the "super.xxx" function call syntax in a class hierarchy, while "getSuperClass" is ok?
It's been a while since i looked at this.

@ianharrigan
Copy link
Author

Is the problem basically in the "super.xxx" function call syntax in a class hierarchy, while "getSuperClass" is ok?

Im not sure im fully following what you mean, but as far as i can tell, yeah, the issue seems to be that "super.xxx" calls the super class at the base of the class tree (thats an assumption on my part), but it certainly doesnt seem to call the "in between ones"

@ianharrigan
Copy link
Author

FYI - @dazKind has also repro'd it and actually, extern classes arent needed at all - i didnt think to test that, i assumed extern was part of the problem

@dazKind
Copy link
Contributor

dazKind commented Sep 4, 2024

I think CppiaClassInfo::getSuperClass() returns an already wrong superId when loading the cppia bytecode, in this case for FakeComponentBase. So I suspect the generator skips the hierarchy somewhere

@dazKind
Copy link
Contributor

dazKind commented Sep 4, 2024

Here is a minimal example:
cppia-superclass.zip

bar@foo /cygdrive/D/Development/regressions
$ make native
haxe native.hxml -debug
haxelib run hxcpp Build.xml haxe -Ddebug -Dhaxe="4.3.4" -Dhaxe3="1" -Dhaxe4="1" -Dhaxe_ver="4.304" -Dhxcpp_api_level="430" -Dhxcpp_smart_strings="1" -Dsource_header="Generated by Haxe 4.3.4" -Dstatic="1" -Dtarget.atomics="1" -Dtarget.name="cpp" -Dtarget.static="1" -Dtarget.sys="1" -Dtarget.threaded="1" -Dtarget.unicode="1" -Dtarget.utf16="1" -Dutf16="1" -Isrc/ -I -IC:\\haxe\\extraLibs/ -IC:\\haxe\\std/cpp/_std/ -IC:\\haxe\\std/
bin/Host-debug.exe
src/FakeTypes.hx:27: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponentBase
src/FakeTypes.hx:18: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponent
src/FakeTypes.hx:11: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeInteractiveComponent
src/FakeTypes.hx:4: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeButton
src/Script.hx:14: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MyFakeButton.someFunction

bar@foo /cygdrive/D/Development/regressions
$ make
haxe host.hxml -debug
haxelib run hxcpp Build.xml haxe -Ddebug -Ddll_export="bin/export_classes.info" -Dhaxe="4.3.4" -Dhaxe3="1" -Dhaxe4="1" -Dhaxe_ver="4.304" -Dhxcpp_api_level="430" -Dhxcpp_smart_strings="1" -Dscriptable="1" -Dsource_header="Generated by Haxe 4.3.4" -Dstatic="1" -Dtarget.atomics="1" -Dtarget.name="cpp" -Dtarget.static="1" -Dtarget.sys="1" -Dtarget.threaded="1" -Dtarget.unicode="1" -Dtarget.utf16="1" -Dutf16="1" -Isrc/ -I -IC:\\haxe\\extraLibs/ -IC:\\haxe\\std/cpp/_std/ -IC:\\haxe\\std/
Link: D:/.hxcpp_cache/hxcpp_runtime/lib/msvc1964_debug_c_hxcpp_runtime.lib
Link: Host-debug.exe
   Creating library Host-debug.lib and object Host-debug.exp
haxe script.hxml -debug
bin/Host-debug.exe
src/Host.hx:7: Hello from cppia HOST
src/FakeTypes.hx:27: >>>>>>>>>>>>>>>>>>>>>>>>> SOME FUNCTION: FakeComponentBase
src/Script.hx:14: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MyFakeButton.someFunction

@Aidan63
Copy link
Contributor

Aidan63 commented Sep 14, 2024

I had a look at this since I got abstract classes working on cppia a while back.

Turning on the cppia logging everything looked alright, it recognised MyFakeButton has the correct parent and someFunction is overridden. I also placed a few breakpoints around the cppia linking functions and when MyFakeButton was linked it appeared to have the full inheritance tree.

image

The problems seems to be registering those classes in the host which are between the cppia child and the root parent, all those intermediate parents have __scriptableFunctions set to null. So when MyFakeButton links someFunction it resolves it against the root parents as thats the only one which registers a script function named someFunction.

Looking at gencpp the function which builds the list of scriptable functions does something very odd when it encounters a function marked as override

let current_virtual_functions_rev clazz base_functions =
   List.fold_left (fun result elem -> match follow elem.cf_type, elem.cf_kind  with
      | _, Method MethDynamic -> result
      | TFun (args,return_type), Method _  ->
          if (is_override elem ) then
             List.map (fun (e,a,r) ->  if e.cf_name<>elem.cf_name then (e,a,r) else  (elem,args,return_type) ) result
          else
             (elem,args,return_type) :: result
      | _,_ -> result
    ) base_functions clazz.cl_ordered_fields
;;

It just maps the existing accumulated results, never adding the overridden function, hence the null scriptable functions. I'm assuming at some point in history it traversed the class tree since thats the only thing I can think of where this code might make sense, but if it once did it does not anymore.

https://github.com/Aidan63/haxe/tree/cppia-overloads

I seem to have a fix in the above branch, I'm a bit nervous about it due to the odd original code and the big comment warning about the order of functions for cppia. But all tests still pass and the posted sample works, so hopefully even if its not perfect its a bit better than before and nothing has regressed.

I'll give it another look tomorrow and open a PR.

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

Successfully merging a pull request may close this issue.

4 participants