HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.17k stars 654 forks source link

Add "final" inference #9400

Open nadako opened 4 years ago

nadako commented 4 years ago

We currently disable some optimizations such as tail recusion elimination and purity inference for non-final instance methods based on the fact that we cannot make assumptions about them, since they can be overriden later by users of haxe-generated code.

While this is a safe bet, I believe it is actually rare when Haxe code is used like that, and it would be more beneficial to actually infer and set final for both classes and methods. It would enable both Haxe and target-native optimizations and would still be safe to use from outside (if target language supports checking for final). It would also benefit code that does not use inheritance much.

Of course, it should be opt-in, so how about -D infer-final?

Simn commented 4 years ago

I was thinking that we need the notion of a Haxe compilation being "self-contained". Perhaps we can even assume this when there is a -main, and then have a define to switch the behavior off (or on in absence of -main).

I feel like there's a better word for that though which eludes me right now.

Gama11 commented 4 years ago

Clearly that's a "final" compilation. ;)

Simn commented 4 years ago

I actually kinda like that, but there's probably some established term for it.

nadako commented 4 years ago

standalone?

RealyUniqueName commented 4 years ago

But what about the complication server? First compilation - no overrides. Second compilation - an override is added, but the parent entity is reused from cache.

Simn commented 4 years ago

Final inference itself can work around that. But yes, if there's an optimization depending on it we would have to reverse-invalidate for sure...

This might then require field-level invalidation first in order to not be a big problem. And that in turn probably requires redesigning the compilation server. :(

khalyomede commented 3 years ago

While I read this thread, I was searching for a duplicate of a proposal I wanted to make for the Haxe compiler. I will put it there because I feel it is relevant on what you are discussing about:

What about making this final not infered, but suggested by the compiler?

For example, given this code:

class Main {
  public static function main() {
    var message = "Hello world";

    trace(message);
  }
}

The compiler could see that the variable message is never reassigned in the scope of the public static function main() method, and warns that it should better be a final message = "Hello world"; instead.

Same would go for classes that are never extended.

I hope it would help not forcing the compiler to make the choice of assuming such class should be final and risk to run into issues mentioned above.

Aurel300 commented 3 years ago

If such a feature is added, it has to be opt-in and maybe a diagnostic in the IDE only. Otherwise there would be thousands of such suggestions in any project or library that I have seen.

kevinresol commented 3 years ago

Perhaps related, I think structure fields should also infer final or at least delay "locking in" the accessors. In the following case, if we can delay locking in the accessor to be (default, default) then it should be able to unify.

class Main {
    static function main() {
        final o = {x: 1}
        foo(o); // error: Cannot unify final and non-final fields
    }

    static function foo(obj:{final x:Int;}) {
        trace(obj.x);
    }
}
nadako commented 3 years ago

@kevinresol I think this is unrelated to the original issue, but it looks sensible to do what you propose, could you create a separate issue?