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

__init__ on java and c# not called at start #8933

Closed
AdrianV opened this issue Nov 6, 2019 · 12 comments · Fixed by #11551
Closed

__init__ on java and c# not called at start #8933

AdrianV opened this issue Nov 6, 2019 · 12 comments · Fixed by #11551
Assignees
Labels
discussion platform-cs Everything related to c# platform-java Everything related to Java
Milestone

Comments

@AdrianV
Copy link
Contributor

AdrianV commented Nov 6, 2019

on Java and C# the initialization order of classes is weird. If they have a __init__ function, this is not called on startup, but on the first time the class is used:

class A {
    public function new() {
        trace("A");
    }

    static function __init__() {
        trace("init A");
    }
}

class B {
    public function new() {
        trace("B");
    }

    static function __init__() {
        trace("init B");
    }
}

class Main {
    static function main() {
        new A();
        new B();
    }
}

gives this out put:

hx-src/Main.hx:7: init A
hx-src/Main.hx:3: A
hx-src/Main.hx:17: init B
hx-src/Main.hx:13: B

on other targets you get this:

hx-src/Main.hx:7: init A
hx-src/Main.hx:17: init B
hx-src/Main.hx:3: A
hx-src/Main.hx:13: B
@RealyUniqueName RealyUniqueName added this to the Release 4.1 milestone Nov 6, 2019
@RealyUniqueName RealyUniqueName self-assigned this Nov 6, 2019
@RealyUniqueName RealyUniqueName added platform-cs Everything related to c# platform-java Everything related to Java labels Nov 6, 2019
@Simn Simn modified the milestones: Release 4.1, Release 4.2 Feb 19, 2020
@Simn
Copy link
Member

Simn commented Jun 4, 2020

IMO we should unspecify this. Trying to hack around the natural initialization behavior of these targets would come with various problems.

@Simn Simn added discussion and removed bug labels Jun 4, 2020
@RealyUniqueName
Copy link
Member

I think the whole idea of __init__ was to guarantee some code run before the main entry point. Otherwise it would be sufficient to write it in static vars initializers.

@Simn
Copy link
Member

Simn commented Jun 5, 2020

That's a noble goal, but it's not compatible with how initialization works on these targets.

In the general case we would have to generate all __init__ code (and nothing else) into the static initializers and then make sure each such class is loaded before executing our application code. As a consequence we couldn't have any initialization for static fields there and would have to move those to the entry point as well. This would also have to become a two pass operation to ensure all __init__ expression are run before any static initialization.

This is just not reasonable.

@AdrianV
Copy link
Contributor Author

AdrianV commented Jun 5, 2020

The current behaviour feels wrong for me. __init__ should be run before main otherwise it should error on those targets. Why can't we have something like this ?

class A {

    static public final __force_init__ = [];
    public function new() {
        trace("A");
    }

    static function __init__() {
        trace("init A");
    }
}

class B {
    static public final __force_init__ = [];
    public function new() {
        trace("B");
    }

    static function __init__() {
        trace("init B");
    }
}

class Main {
    static final __force_init_A__ = A.__force_init__;
    static final __force_init_B__ = B.__force_init__;
    static function main() {
        trace('main');
        new A();
        trace('here');
        new B();
    }
}

yeah its ugly, but now I get a consistent output on these targets. The only difference now is that __init__ is called after the static initializer for these targets, but still before main.

@Simn
Copy link
Member

Simn commented Jun 5, 2020

The only difference now is that init is called after the static initializer for these targets

But that is just trading one inconsistency for another.

@AdrianV
Copy link
Contributor Author

AdrianV commented Jun 5, 2020

yes, but __init__ is some black magic and only used if someone needs it. In the current situation a library like hxbit does not work on java or cs. And we could/should make this behaviour consistent for all targets by specification: __init__ does not guarantee that the static initializers are run, but __init__ is run before main.
Currently there is no guarantee for __init__ at all. I could even run after main or not at all.

@Simn
Copy link
Member

Simn commented Jun 5, 2020

I would be willing to change it so the compiler collects all classes that have an __init__ and then emits code that references them before main() is called. That wouldn't affect startup time too much because these classes are rare.

However, we still cannot comply with the original specification which says that all __init__ code is executed before any static initialization.

@AdrianV
Copy link
Contributor Author

AdrianV commented Jun 5, 2020

However, we still cannot comply with the original specification which says that all init code is executed before any static initialization.

If that is the specification than it is broken on some targets anyway :)

class Main {
    static var test = [1,2,3];
    
    static function main() {
        trace("Haxe is great!");
    }
    
    static function __init__() {
        trace(test);
    }
}

on Js I get:
src/Main.hx:9: undefined
src/Main.hx:5: Haxe is great!

on interp I get:
src/Main.hx:9: [1,2,3]
src/Main.hx:5: Haxe is great!

@RealyUniqueName
Copy link
Member

I thought __init__ is specified to run before main entry point, not any static initialization.

Anyway I'd prefer __init__ to not exist. But it's too late to remove it.

@AdrianV
Copy link
Contributor Author

AdrianV commented Jun 5, 2020

at least we can agree, that it is not following any specification up to now....
IMHO it should run before main, otherwise we should drop it, or error on targets where it is not possible.
If possible it should run before static initialization of its module, not after - and that is what it does on most targets.

@Simn
Copy link
Member

Simn commented Jun 5, 2020

If possible it should run before static initialization of its module, not after - and that is what it does on most targets.

I think it does that on all targets already.

@AdrianV
Copy link
Contributor Author

AdrianV commented Jun 5, 2020

on eval it runs after static initialization as shown above. And on cs and java it runs unpredictable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion platform-cs Everything related to c# platform-java Everything related to Java
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants