Advanced Types
Up to now, we have seen the following types :
- class instance
- enum instance
- dynamic
There are several additional important types.
Anonymous
An anonymous type is the type of an anonymously declared object. It is also the type of a Class identifier (corresponding to all the static fields) or an Enum identifier (listing all the constructors). Here's an example that shows it.
enum State { on; off; disable; } class C { static var x : Int; static var y : String; function f() { // print { id : Int, city : String } type({ id : 125, city : "Kyoto" }); } function g() { // print { on : State, off : State, disable : State } type(State); } function h() { // print { x : Int, y : String } type(C); } }
Anonymous types are structural, so it's possible to have more fields in the value than in the type :
var p : { x : Int, y : Int } = { x : 0, y : 33, z : -45 };
Typedef
You can define type definitions which are some kind of type-shortcut that can be used to give a name to an anonymous type or a long type that you don't want to repeat everywhere in your program :
typedef User = { var age : Int; var name : String; } // .... var u : User = { age : 26, name : "Tom" };
// PointCube is a 3-dimensional array of points typedef PointCube = Array<Array<Array<Point>>>
Typedef are not classes, they are only used for typing.
Functions
When you want to define function types to use them as variables, you can define them by listing the arguments followed by the return type and separated with arrows. For example Int -> Void is the type of a function taking an Int as argument and returning Void. And Color -> Color ->Int takes two Color arguments and returns an Int.
class C { function f(x : String) : Int { // ... } function g() { type(f); // print String -> Int var ftype : String -> String = f; // ERROR : should be String -> Int } }
Unknown
When a type is not declared, it is used with the type Unknown. The first time it is used with another type, it will change to it. This was explained in more details in type inference. The id printed with the Unknown type is used to differentiate several unknowns when printing a complex type.
function f() { var x; type(x); // print Unknown<0> x = 0; type(x); // print Int }
The diversity of types expressible with haXe enable more powerful models of programming by providing high-level abstractions that don't need complex classes relationships to be used.
Extensions
Extensions can be used to extend either a typedef representing an anonymous type or to extend a class on-the-fly.
Here's an example of anonymous typedef extension :
typedef Point = { var x : Int; var y : Int; } // define 'p' as a Point with an additional field z var p : {> Point, z : Int } p = { x : 0, y : 0, z : 0 }; // works p = { x : 0, y : 0 }; // fails
For classes, since they don't define types, you need to use a cast when assigning, it's unsafe so be careful :
var p : {> flash.MovieClip, tf : flash.TextField }; p = flash.Lib._root; // fails p = cast flash.Lib._root; // works, but no typecheck !
You can also use extensions to create cascading typedefs :
typedef Point = { var x : Int; var y : Int; } typedef Point3D = {> Point, var z : Int; }
In that case, every Point3D will of course be a Point as well.