The Haxe Type System

HaXe is an object-oriented programming language. However, unlike some other languages, Haxe is not a "pure" OO language, in the sense that everything in Haxe is not an object. Haxe instead promotes the idea that different types carry more meaning than one single monotheistic Object type.

Haxe then separates types into different "type-groups". These groups are the following :

Class Instance

Like many OO languages, the most commonly used type in Haxe is the class instance.

It's possible to declare a class with the class keyword :

class Point {
    var x : Int;
    var y : Int;
    public function new(x,y) {
        this.x = x;
        this.y = y;
    }
    public function toString() {
        return "Point("+x+","+y+")";
    }
}

In this example the class has a constructor (the new function) which is called when an instance is created, and also has two fields x and y with type Int, and has one method toString which will be called when we want to display an instance representation.

Methods in Haxe are referenced by name, so you can have only one method or field with a given name : it's not possible to reuse the same name for different methods in the same class.

You can create an instance of a given class by using the new keyword :

var p = new Point(-1,65);
trace(p); // will call p.toString() and display it

In this example, the type of the variable p is Point, which is a shortcut for saying an instance of the Class Point.

Inheritance

One class can inherit another, by using the extends keyword. The subclass cannot redefine the same fields, but can override the methods as long as it doesn't change the type of the method :

class Point3D extends Point {
    var z : Int;
    public function new(x,y,z) {
        super(x,y);
        this.z = z;
    }
    override function toString() {
        return "Point3D("+x+","+y+","+z+")";
    }
}

When a class inherits from another class, it becomes a subtype of the parent class. It then means that every Point3D instance is also a Point instance, as the following example shows :

var p : Point = new Point3D(0,0,0);

Interfaces

A class can also implement one or several interfaces, which can detail which variables and/or methods a given class should contain or implement :

interface IsPrintable {
    function toString() : String;
}

interface HasX {
    var x : Int;
}

class AnotherPoint extends Point implements IsPrintable implements HasX {
}

Note: Before Haxe 3.0, implements declarations should have been comma-separated.

Since AnotherPoint extends Point it already contains a x field, which is required by the HasX interface and contains a toString method as required by the IsPrintable interface. It doesn't need to declare the fields and methods required by the interfaces but may declare/define additional fields and functions as necessary.

Interfaces types can also be used as subtypes, for instance :

var p : IsPrintable = new AnotherPoint(); // OK

This is accepted by the Haxe compiler because AnotherPoint implements IsPrintable, whereas the following will cause an error :

var p : IsPrintable = new Point(); // ERROR

This causes an error because the "Point" class does not implement the "IsPrintable" interface either directly or indirectly.

Statics

Properties

Structure

In addition to classes, Haxe also provides a structure type :

var p = { x : -1, y : 65 };

In this example, the type of the variable p will be the structure { x : Int, y : Int }, consisting of two fields x and y, both of type Int.

Structural Subtyping

Structures use structural subtyping rules, so the Haxe compiler will check that all fields declared are present, and display an error if a field is missing :

var p : { x : Int, y : Int }; // declare a typed variable
p = { x : -1, y : 65 }; // OK
p = { x : -1 }; // ERROR : field y is missing

But using structural subtyping also means that you can hide extra fields, in which case you will not be able to access them anymore :

p = { x : -1, y : 65, z : 45 }; // OK, hiding field z
trace(p.z); // ERROR, p has no field z

Structures do not just allow structural subtyping between themselves - you can also bind a class instance to structure variable :

p = new Point(-1,65);

The following will work, since the instance of the class Point has both x : Int and y : Int fields.

Structures are a perfect way to define some common traits between otherwise unrelated classes. In many languages, this is done through interfaces. Haxe also has interfaces which can be used for that, but it requires you to carefully design your application structure in order to ensure that good interfaces are defined.

Structures can act as "implicit interfaces" since the original class does not need to be modified in order to be able to be used as a structure.

For example the following method will accept all class instances and structures which have two fields x and y, each of type Int :

function add( s : { x : Int, y : Int } ) {
    return s.x + s.y;
}

Methods

Enum Instance

Function

Typedef

Dynamic

Unknown

Abstract

An abstract type is only defined by a name, but can have subtype relationships with other abtract types.

Example :

typedef Void; // defines an abstract type "Void"
typedef Float; // defines an abstract type "Float"
typedef Int < Float; // defines an abstract type "Int" 
                    // which is also a subtype of Float,
                    // meaning that every Int is also a Float

Note : Abstract types are not yet part of the language syntax, so you can't define your own abstract types this way (as of haxe 2.03), although this should be included in future releases. Currently, Int and Float are defined as classes and Void as an empty enum

version #19848, modified 2013-12-16 09:06:37 by seeker1983