Architecture

edit

Compiler

edit

The Haxe compiler is separated into one frontend and multiple backends. The frontend is responsible for parsing and type-checking the input language, applying macros, general optimizations, various transformations, and for producing the intermediate representation of the code, the typed abstract syntax tree (AST). Each of the backends is responsible for translating that AST into either sourcecode or bytecode for the respective target.

The compiler is written in Ocaml and has exceptional performance. It can be run in server-mode (command-line: haxe --wait [host:]port ) to provide code completion for IDEs and maintain a cache, to speed up compilation even more.

Targets

edit

A target, in the context of Haxe, is an ambiguous term. It is used for platforms that provide access to core-APIs (language and bytecode targets), for the compiler-backends that are responsible for generating the respective code, and for runtimes with specific APIs that go beyond the core language support (platform-targets).

Language and Bytecode Targets

edit

There are targets that produce bytecode (Neko, SWF, SWF8), sourcecode, that has to be compiled by a third-party compiler (C++, C#, Java), and source-code, that is being passed as-is to the respective runtime (JavaScript, PHP). Each provides specific mechanisms to interact with low-level aspects of the target-language to ease development. Targets that produce source-code e.g. offer a mechanism to embed code written in the target-language directly into haxe code.

Platform Targets

edit

For most of the targets, multiple runtimes with different purposes exist. JavaScript, for instance, is in wide-spread use as a scripting language in browsers, game-engines, office-applications, as server-side language for runtimes like NodeJs, and much more. While Haxe supports all these runtimes with a single JavaScript target, the respective runtime APIs differ. Extern type definitions ("extern class" in Haxe) allow to describe the types of platform-native APIs, as well as those of runtimes and libraries written in the target language, to the Haxe compiler, so that static type-checking can be applied.

Since many of these platform targets run on multiple platforms themselves, there are very many options to deploy code written in haxe. Proper separation of platform independent code from the platform specific parts (e.g. the different filesystem APIs in AIR and NodeJS) ...


Code Generator Platform Target Common usage Since Haxe Version Comments
AVM Flashplayer Desktop/Browser 1.0 (Nov. 2005)
AVM2 Flashplayer Desktop/Browser 2.0 (Aug. 2006)
" AIR Desktop, Mobile
" Tamarin Server,Desktop
Javascript Browser/HTML5 Desktop, Mobile 1.0 (Nov. 2005)
" NodeJS Server,Desktop
" PhoneGap Mobile
" Sencha Mobile
Neko NekoVM Server,Desktop 1.0 (Nov. 2005)
C++ hxcpp Server,Desktop,Mobile 2.04 (April 2009)
Java JVM Server, Desktop 2.10 (April 2012) experimental
C# .NET Server, Desktop, Mobile 2.10 (April 2012) experimental
PHP PHP Server 2.0 (July 2008)

Language

edit

Type System

edit

Haxe is a statically typed language. It has a rich type system that offers classes, interfaces, function/method types, anonymous types, algebraic data types (ATDs, called "enum" in Haxe), abstract types, and generalized algebraic datatypes (GADTs). Classes, ADTs, GADTs and function types allow parametric polymorphism based on type erasure, sometimes also called "Generics" in object oriented programming languages.

Bounded quantification is also part of the feature set: type parameters can be constrained to a set of zero or more types.

Haxe doesn't offer variance annotations for type parameters, the type constructors are always invariant in their parameter types.

Subtype polymorphism is supported via standard, single-inheritance.

Further, haxe supports both structural typing and nominal typing. To ease the burden on the programmer, without sacrificing type safety, Haxe supports type-inference, which in many cases alleviates the need to write out types explicitly.

Classes

edit

Classes (keyword "class") in Haxe are similar to those in e.g. Java or AS3. Their fields can be either methods, variables or properties, each static or per instance respectively. Haxe supports the accessors "public" and "private". as well as more advanced methods for access control (ACL, link, whatever), that are denoted using annotations. Methods and static variables of constant values can be inlined using the "inline" keyword.

class Person {

    var birth:Date;
    var name:String;

    public function age():Int return Date.now().getFullYear()-birth.getFullYear()
    
}

Interfaces

edit

Interfaces in Haxe are very similar to those in e.g. Java.

interface ICreature {

    function age():Int;

}

class Fly implements ICreature {
    public function age():Int;
}

Algebraic Data Types

edit

Enums (keyword "enum") in Haxe are commonly referred to as algebraic data types (short: ADT) in functional languages. Haxe also supports generalized algebraic data types (GADT).

Prominent uses for ADTs are e.g. Option, Either and List:

enum Option<T> {
    Some(v:T);
    None;
}

enum Either<T,U> {
    Left(v:T);
    Right(v:U);
}

enum ConsList<T> {
    Nil;
    Cons(head:T,tail:ConsList<T>);
}

Anonymous Types

edit

Anonymous types are defined by denoting their structure explicitly, they can be given an alias by using a type definition (keyword "typedef"):

typedef Anon = { a:Int, b:String, c:Float->Void };


Function Types

edit

Functions are first-class values in Haxe. Their type is denoted by using arrows between argument types, and the argument type(s) and return type respectively, as common in many functional languages. However, unlike in prominent examples like Haskell or the ML-family of languages, not all functions are unary functions (functions with one argument only), and in Haxe, functions can't be partially applied per default. Therefore the following type signatures have different semantics than in the aforementioned languages. The type F is a function that takes an Int and a String as arguments, and returns a value of type Float.

The same notation in a language with unary functions only, would refer to a function that takes an Int as argument, and returns a function of Type String->Float.

Types F2 and F3 denote the same type. Both are binary functions that return a binary function of type F. For F3 the syntax to declare a function type within a function type is used.

typedef F = Int->String->Float;

typedef F2 = Int->String->F;
typedef F3 = Int->String->(Int->String->Float);

Abstract Types

edit

Abstract Types, along with GADTs are the latest addition to the Haxe type system. They allow to reuse existing types for specific purposes, like implementing types for units of measurement, to greatly reduce the risk of mixing up values of the same underlying type, but with different meanings (e.g. miles vs. km).

Let's assume a library that uses the metric system per default, but has to deal with legacy data, that still uses miles for distances in certain places. Whenever we encounter miles, we want an automatic conversion to kilometers, but not in the opposite direction.

So we define two abstracts, that capture those requirements for us:

abstract Kilometer(Float) {
    public function new(v:Float) this = v
}

abstract Mile(Float) {
    public function new(v:Float) this = v
    @:to public inline function toKilometer():Kilometer return (new Kilometer(this/0.62137))
}

class Test {
  static var km:Kilometer;
  static function main(){
    
    var one100Miles = new Mile(100);
    km = one100Miles;
    
    trace(km); // et voila! 160.935
  }
}

As the example shows, no explicit conversion is required for the assignment "km = one100Miles;" to do the right thing.

Structural Typing

edit

Structural typing plays a major role in many functional programming languages, and only to a much lesser extent in common OOP languages. Unlike in (exclusively) nominative type systems, the equality of two types isn't established by some kind of name tag, but rather by the structure of a type. Structural types can be thought of as implicit interfaces:

class FooBar {
   
   public function new(){ foo=1; bar="2";}
   
   public var foo:Int;
   public var bar:String;

   function anyFooBar(v:{foo:Int,bar:String}) trace(v.foo)
   
   static function test(){
        var fb = new FooBar();
        fb.anyFooBar(fb);
        fb.anyFooBar({foo:123,bar:"456"});
   }
}


Dynamic

edit

It is unfortunate, but as a language that has to interface with all sorts of platforms, sometimes the need arises to eschew the safety net, that the strong static type system provides the Haxe developer with. For those situations, there is Dynamic. It unifies with any other type, completely circumventing the type system.

Features

edit

Metaprogramming

edit

Extension Methods

edit

Dead Code Elimination

edit

Pattern Matching

edit

Remoting

edit

History

edit

mtasc, AS3 blabla

Answers

edit