-
-
Notifications
You must be signed in to change notification settings - Fork 661
Breaking changes in Haxe 4.0.0
function set_some(value) {
var old = some;
some = value;
rollbacks.push(function() some = old); // <-- bypasses setter now as it should
}
Use -D haxe3compat
to get warnings pointing to places that need to be fixed.
final
is a new keyword and can no longer be used as an identifier.
The Null<T>
type is now @:coreType abstract
instead of a typedef
to T
.
It still supports implicit conversion from and to T
, as well as forwarding
any field access to T
, so its basic usage shouldn't be affected at all.
However, this change affects macros. Becasue it's not a typedef
now, it won't be
automatically followed by Context.follow
and it won't be matched by the TType
constructor. Instead it's now represented as a TAbstract
instance, so if a macro
is handling Null
specifically, it needs to be changed to match TAbstract
instead of
TType
. Also if the macro is handling TAbstract
, e.g. by recursing into its underlying
type, an additional match for the Null
case might be needed, unless it's already handling
abstracts with the @:coreType
metadata.
The reason for this change is mainly to cleanup the inconsistency and confusion about Null
within compiler and macro source. That is, on most static platforms, the nullable type is
often different than a non-nullable type, for e.g. basic types (Int,Bool,etc), so having Null<T>
represented as a mere type alias (which is what typedef
is) leads to bugs and general confusion.
Moreover, having an abstract Null<T>
type sets the ground for possible future exploration regarding null-safety features, because with abstract types we can control implicit casting and variance easier.
Related PR: https://github.com/HaxeFoundation/haxe/pull/6380
A new constructor were added to the haxe.macro.Type.TypedExprDef
enum: TEnumIndex(e1:TypedExpr)
. It represents access to a enum index value and is generated by the pattern matcher.
Before this node was introduced, the pattern matcher was generating a (potentially inlined) Type.enumIndex
call that was hard to distinguish later in the optimization filters and generators.
Related PR: https://github.com/HaxeFoundation/haxe/pull/6364
Identifiers that are not bound to a known field or variable are now represented by a special haxe.macro.Type.TypedExprDef
constructor: TIdent(s:String)
. These identifiers are most often
introduced by the use of untyped
(e.g. untyped __js__
).
Before this node, such identifiers were represented by a TLocal
node pointing a fake local variable with @:unbound
metadata. This solution wasn't perfect, because compiler/macro developer would expect TLocal
to point an actually declared variable, so having to check whether a given local variable is unbound every time is error-prone.
Related PR: https://github.com/HaxeFoundation/haxe/pull/6424
The interpreter used for running scripts and executing macros has been rewritten for better performance and maintainability. There are two things to consider regarding backward compatibility in this change:
First, the target name for the interpreter is now eval
, not neko
, so if the code contains #if neko
conditional compilation implying that it also affects interpreter, that has to be changed to #if eval
or #if (neko || eval)
. The macro
define is of course still present when running macros.
Second, because of the new target now has a JIT-compilation step, it's a bit more strict about compiling code that was meant for another target. For example, if a module with your macro function also contains a method with code like untyped __js__
, the previous interpreter would not complain about it unless you actually execute that method. The new interpreter will fail at JIT-compilation stage. To fix this, the code that is not meant to run on eval should be skipped, for example by fencing it with #if <target-define>
or #if !macro
, or by moving it into a separate module that won't be loaded in the interpreter context.
Related PR: https://github.com/HaxeFoundation/haxe/pull/6319
Related blog post: http://haxe.org/blog/eval/
Haxe now expects the source files (.hx
) to be UTF-8 encoded and positions reported and expected by the compiler now contain character offsets instead of byte offsets.
This is an important change for IDE support maintainers: all display query offsets and all reported positions must be treated as character-based rather than byte-based.
This makes haxe report proper positions for source files containing multi-byte characters, such as Cyrillic, CJK and others. This also should make it easier for editors to integrate with haxe ide services, since they mostly work with character offsets as well. If the editor has the handling position conversion by e.g. encoding/decoding the file on-request, this should be disabled for Haxe 4.
Related issue: https://github.com/HaxeFoundation/haxe/issues/5163
Related PR: https://github.com/HaxeFoundation/haxe/pull/6172
If your IDE have Haxe 3.x support, you can add -D old-error-format
to keep compiler completion working using previous behavior. Other advanced completion services will not work with bytes position.
Haxe now reports both line and column number starting from 1. This is more consistent and is what a lot of editors expect when processing build output for capturing error messages.
If you're parsing the position string (e.g. main.hx:3: characters 17-25
) for further processing, please note that characters
numbers are now 1-based. This can be disabled with -D old-error-format
compiler argument.
Related PR: https://github.com/HaxeFoundation/haxe/pull/6391
Haxe 4 now supports short arrow function syntax in the form of (a, b) -> a + b
which is equivalent to function(a, b) return a + b
.
While it's an obvious feature for language users, IDE maintainers will need to add support for this new syntax. In short:
// no args
() -> expr
// with args
(arg1, arg2) -> expr
// args with type hints
(arg1:Type1, arg2:Type2) -> expr
// return type hint is not supported for arrow functions due to syntax ambiguity,
// one can use type-check syntax in the function expression
(arg1:Type) -> (expr:ReturnType)
// single-arg-no-type-hint convenience special case (no parenthesis required)
arg -> expr
Related proposal: https://github.com/HaxeFoundation/haxe-evolution/blob/master/proposals/0002-arrow-functions.md
In addition to the old Int->Void
function type syntax, Haxe 4 now has new syntax for specifying function types with support for argument names.
// no args
() -> Void
// unnamed args
(Int, String) -> Bool
// named args
(name:String) -> Void
// named, unnamed and optional args mixed
(arg1:Type1, ?arg2:Type2, Type3) -> Ret
Related proposal: https://github.com/HaxeFoundation/haxe-evolution/blob/master/proposals/0003-new-function-type.md
The classes in haxe.unit have been removed. They are still available from the hx3compat library. For more elaborate unit testing frameworks, consider using utest or munit.
Some occurrences of List
in the standard library have been replaced with Array
. This might require some small changes in user code.
While usage remains the same, it is no longer possible to use haxe.xml.Fast as a class (e.g. extending it or using reflection on it).
The syntax T:(A, B)
is no longer supported and has been replaced by T : A & B
. We decided to break this because there was a syntactic conflict.
See https://github.com/HaxeFoundation/haxe/pull/7127
- Static extensions no longer resolve on an implicit
this
type. This was a little-known feature which could affect resolution order in some instances (related: https://github.com/HaxeFoundation/haxe/issues/6036) - Static extensions no longer apply abstract field-casts. (https://github.com/HaxeFoundation/haxe/issues/5924)
Learn Haxe: Introduction | Manual | API | Try Haxe | Haxe Library Manager | Code Cookbook
Connect: GitHub | Stack Overflow | Forum | Discord | Gitter | Twitter | Facebook