An abstract type is a compile-time construct which is represented in a different way at runtime. This allows giving a whole new meaning to existing types.
Externs can be used to describe target-specific interaction in a type-safe manner.
Data can easily be grouped in anonymous structures, minimizing the necessity of small data classes.
var point = {x: 0, y: 10}; point.x += 10;
Create and populate arrays quickly using for loops and logic.
var evenNumbers = [for (i in 0...100) if (i & 1 == 0) i];
Create and populate maps quickly using for loops and logic.
var primality = [for (i in 0...100) i => isPrime(i)];
Classes, interfaces and inheritance:
Haxe allows structuring code in classes, making it an object-oriented language. Common related features known from languages such as Java are supported, including inheritance and interfaces.
Conditional Compilation allows compiling specific code depending on compilation parameters. This is instrumental for abstracting target-specific differences, but can also be used for other purposes, such as more detailed debugging.
#if js js.Browser.alert("Hello"); #elseif sys Sys.println("Hello"); #end
(Generalized) Algebraic Data Types:
Structure can be expressed through algebraic data types (ADT), which are known as enums in the Haxe Language. Furthermore, Haxe supports their generalized variant known as GADT.
enum Result { Success(data:Array<Int>); UserError(msg:String); SystemError(msg:String, position:PosInfos); }
Functions can be designated as being inline, allowing their code to be inserted at call-site. This can yield significant performance benefits without resorting to code duplication via manual inlining.
Iterating over a set of values, e.g. the elements of an array, is very easy in Haxe courtesy of iterators. Custom classes can quickly implement iterator functionality to allow iteration.
for (i in [1, 2, 3]) { trace(i); }
Functions in Haxe are not limited to class fields and can be declared in expressions as well, allowing powerful closures.
var buffer = ""; function append(s:String) { buffer += s; } append("foo"); append("bar"); trace(buffer); // foobar
Add metadata to fields, classes or expressions. This can communicate information to the compiler, macros, or runtime classes.
class MyClass { @range(1, 8) var value:Int; } trace(haxe.rtti.Meta.getFields(MyClass).value.range); // [1,8]
Existing classes and other types can be augmented with additional functionality through using static extensions.
using StringTools; " Me & You ".trim().htmlEscape();
Strings declared with a single quotes are able to access variables in the current context.
trace('My name is $name and I work in ${job.industry}');
Any function can be applied partially, providing the values of some arguments and leaving the rest to be filled in later.
var map = new haxe.ds.IntMap(); var setToTwelve = map.set.bind(_, 12); setToTwelve(1); setToTwelve(2);
Complex structures can be matched against patterns, extracting information from an enum or a structure and defining specific operations for specific value combination.
var a = {foo: 12}; switch a { case {foo: i}: trace(i); default: }
Variable class fields can be designed as properties with custom read and write access, allowing fine grained access control.
public var color(get,set); function get_color() { return element.style.backgroundColor; } function set_color(c:String) { trace('Setting background of element to $c'); return element.style.backgroundColor = c; }
The access control language feature uses the Haxe metadata syntax to force or allow access classes or fields.
Type Parameters, Constraints and Variance:
Types can be parametrized with type parameters, allowing typed containers and other complex data structures. Type parameters can also be constrained to certain types and respect variance rules.
class Main<A> { static function main() { new Main<String>("foo"); new Main(12); // use type inference } function new(a:A) {} }