Skip to content

Breaking changes in Haxe 5.0.0

Rudy Ges edited this page Mar 5, 2024 · 4 revisions

Preparing for migration

We introduced a new haxe-next define in 4.3.x versions, which when defined (-D haxe-next) will enable some behavior from next versions of Haxe, allowing you to start migrating your code.

Currently (with Haxe 4.3.4), haxe-next define will:

More may be added later while we move closer to Haxe 5.0 release.

bind typing with optional arguments

Changed in #11533

Haxe 4 hides trailing optional arguments when using bind on a function:

function f(notOpt:Int, ?opt:String) {}

function main() {
  var fBind = f.bind(1);
  $type(fBind); // () -> Void
}

In Haxe 5, this is now typed as (?opt : Null<String>) -> Void which might cause unification errors.

There are two ways to address this, depending on your use case:

Trigger Haxe 5 behavior in Haxe 4

The easiest way to address this is to use explicit _ for all trailing optional arguments:

function f(notOpt:Int, ?opt:String) {}

function main() {
	var fBind = f.bind(1, _);
	$type(fBind); // (?opt : Null<String>) -> Void
}

This gives the same result in both Haxe 4 and 5.

Haxe 4 typing compatibility with Haxe 5

In Haxe 4, due to trailing optional arguments being hidden, using bind on a function with optional arguments where a function with no such arguments is expected would work:

function f(notOpt:Int, ?opt:String) {}
function foo(cb:Void->Void) {}

function main() {
  var fBind = f.bind(1);
  $type(fBind); // () -> Void
  foo(fBind); // Ok
}

In Haxe 5, compiler will complain with (?opt : Null<String>) -> Void should be () -> Void.

This can be fixed by explicitly adding null for optional args:

function f(notOpt:Int, ?opt:String) {}
function g(notOpt:Int, alsoNotOpt:Bool, ?opt:String) {}
function foo(cb:Void->Void) {}
function bar(cb:Bool->Void) {}

function main() {
  var f1 = f.bind(1, null);
  $type(f1); // () -> Void
  foo(f1); // Ok

  // And if you need to skip arguments:
  var g1 = g.bind(1, _, null);
  $type(g1); // (alsoNotOpt : Bool) -> Void
  bar(g1); // Ok
}

You can also use a lambda instead of bind:

function f(notOpt:Int, ?opt:String) {}
function foo(cb:Void->Void) {}

function main() {
  var fLambda = () -> f(1);
  $type(fLambda); // () -> Void
  foo(fLambda); // Ok
}

Those solutions work in both Haxe 4 and 5.

Macro build order consistency fixes

Changed in #11582

TODO

Don't infer string on concat

Changed in #11318

TODO

Rework module resolution

Changed in #11168

TODO

Delay typer creation to after init macros

Changed in #11323
See also removed API from haxe.macro.Compiler #11540

TODO

Don't create a class field for every enum field

Changed in #11452

TODO
This can have an impact on macros that look at the anon fields

Only set cf_expr_unoptimized if we think we need it

Changed in #11462

TODO