Skip to content

What's new in Haxe 4

Dan Korostelev edited this page Feb 8, 2019 · 50 revisions

New function type syntax

We're introducing the new syntax for specifying function types, now with clear separation of arguments from the return type and with support for argument names, which is very helpful for code self-documenting and better IDE support.

Example:

(name:String, age:Int)->Bool

Evolution proposal

Note that the old syntax is still supported, but the new one is preferable.

Arrow function syntax

Haxe now finally has the long-awaited arrow function syntax (a.k.a. short lambdas)! This is useful for code that has a lot of "short-and-sweet" callback functions, especially for the code written in the functional paradigm or the code that has to deal with asynchronous operations.

Example:

(a, b) -> a + b

Evolution proposal

Null-safety (experimental opt-in)

@:nullSafety

Final fields and locals

final a = 5

(can't mutate)

Final classes / interfaces without @:

final class Foo {}
final interface Bar {}

Unicode

"".length == 1

Eval

faster interpreter -> faster macros and scripts debugging support \o/

HashLink

Haxe 4 goes with HashLink - the new high-performance run-time developed specifically for Haxe, featuring bytecode+JIT and C output, simple C interop and access to low-level numeric types and pointers.

Call-site inlining

It's now possible to inline function calls and inlineable class instantiations by specifying inline keyword before call/new expression:

inline f()
inline new Obj()

Evolution proposal

Auto-"using" for types

It's now possible to enable static extensions (a.k.a. using) for a type at that type's declaration place. This is particularly useful for adding additional methods for enum types, for example:

@:using(Outcome.OutcomeTools)
enum Outcome<T> {
	Success(value:T);
	Failure(error:String);
}

class OutcomeTools {
	public static function sure<T>(outcome:Outcome<T>):T {
		switch outcome {
			case Success(value): return value;
			case Failure(error): throw error;
		}
	}
}

The static extension methods from OutcomeTools can then be used without adding explicit using Outcome.OutcomeTools; statement:

class Main {
	static function main() {
		var outcome = load();
		outcome.sure();
	}
	static function load():Outcome<String> {
		return Success("Done!");
	}
}

Abstract "resolved" field set support

Abstract types now support the "set" version of @:op(a.b) operator functions (aka "resolve")

abstract DotAccess<T>(Map<String,T>) {
	public function new() {
		this = new Map();
	}

	@:op(a.b) function get(field:String):T {
		return this[field];
	}

	@:op(a.b) function set(field:String, value:T):T {
		return this[field] = value;
	}
}

...

var d = new DotAccess();
d.hello = 5;
trace(d.hello);

Key-value iterators

The for loop syntax now supports iteration over key+value pairs with a new syntax:

for (key => value in collection) {}

User-defined structures can support this by conforming to the new KeyValueIterable protocol.

Evolution proposal

Inline XML syntax

var a = <hi/>;

This will be available for macro processing as @:markup "<hi/>". XML strings are supposed to be parsed with a custom parser.

Simple example to convert inline XML to a string with a macro function:

class Test {
  static function main() {
    var dom = jsx(<hi/>);
    trace(dom);
  }
  static macro function jsx(expr) {
    return switch expr.expr {
      case EMeta({name: ":markup"}, {expr: EConst(CString(s))}):
      	macro $v{"XML MARKUP: " + s};
      case _:
        throw new haxe.macro.Expr.Error("not an xml literal", expr.pos);
    }
  }
}

A more complete example of parsing JSX-like syntax in @ncannasse's DOMKit: https://github.com/ncannasse/domkit/blob/master/domkit/MarkupParser.hx

Syntax for optional fields in "full" anon structs notation

Optional fields in structure types defined in the "full" notation can now also be marked as such with ?, just like in the short notation. Previously one had to use @:optional metadata which didn't look good and was error-prone.

{ ?f:Int } // short notation
{ var ?f:Int; } // full notation

Enum abstract without @:

enum abstract E(T) {}

Auto-numbering for enum abstracts

enum abstract E(Int) {
  var A; // 0
  var B; // 1
}
enum abstract E(String) {
  var A; // "A"
  var B; // "B"
}

Extern fields without @:

extern inline function f(...) {}

Removed implements Dynamic

Use custom abstracts if you need something like that

Added "type intersection" syntax

A & B (currently only for structures and type param constraints)

Removed comma-separated type param constraints syntax

C<T:(A,B)> now should be C<T:A&B>

Empty Map literals

var map:Map<Int, String> = [];

haxe.ds.ReadOnlyArray

var a:haxe.ds.ReadOnlyArray<Int> = [1, 2, 3];
a.push(4); // haxe.ds.ReadOnlyArray<Int> has no field push

New IDE services protocol

more features, json-based, currently undocumented, implemented in haxe language server and used in vshaxe

https://github.com/vshaxe/vshaxe/wiki/What%27s-New-in-2.0.0

Reworked command-line arguments and help message

Re-generated HTML externs