Object Oriented Programming

Classes

We will quickly introduce the structure of classes that you might already be familiar with if you've done some OO programming before :

    package my.pack;
    /*
        this will define the class my.pack.MyClass
    */
    class MyClass {
        // ....
    }

A Class can have several variables and methods.

    package my.pack;

    class MyClass {

        var id : Int;

        static var name : String = "MyString";

        function foo() : Void {
        }

        static function bar( s : String, v : Bool ) : Void {
        }
    }

All class variables must be declared with a type (you can use Dynamic if you don't know which type to use). Function arguments and return types are optional but are still strictly checked as we will see when introducing type inference.
Non-static variables may not have an initial value. Since haxe 2.10 they may have an intial value if that value is a constant. Declaring the type is not required in that case.
Static variables can have an initial value, although it is not required.

Variables and methods can have the following flags :

  • static : the field belongs to the Class itself and not to instances of this class. Static identifiers can be used directly in the class itself. Outside of the class, it must be used with the class name (for example : my.pack.MyClass.name).
  • dynamic: the field can be dynamically rebound.
  • override: the field is being overridden in a subclass.
  • public : the field can be accessed from outside of the class.
  • private : corresponds to protected, as used in other languages such as ActionScript, Java and PHP, the field access is restricted to the class itself and to classes that subclass or extend it. By default, all fields are private.
    Consider the following two special cases where access to private fields is also permitted:
  • 'Class-private'
    class Foo {
        private var a:Int;//This field can be accessed from ALL code within this class
        function b(f:Foo) {
            trace(f.a);
        }
    }
  • Access to the private members of common base classes (since haxe 2.10)
    class Foo {
        private var nr = 0;
        public function new()    {
        }
    }
    class Bar extends Foo {
        public function new() {
            super();
        }
    }
    class Baz extends Foo {
        public function new() {
            super();
            var bar = new Bar();
            bar.nr = 1;//because Baz and Bar share the same base class Foo where 'nr' is defined, access to private field nr is permitted here
        }
    }

Class Initializer

The class can optionally specify a static intiailizer function to be run before any other aspects of the class are initialized. This function must be declared as follows:

    static function __init__()
    {
         ...;
    }

This function will be run when the application first starts up, before any static member variables of the class have been initialized. Note that try/catch exception blocks cannot be used inside __init__.

The compiler will detect references to other classes from within an __init__ function and ensure that classes which are thus referenced have their own __init__ function called first.

Constructor

The class can have only one constructor, which is the non-static function called new. This is a keyword that can also be used to name a class function :

    class Point {
        public var x : Int;
        public var y : Int;

        public function new() {
            this.x = 0;
            this.y = 0;
        }
    }

Constructor parametrization & overloading :

    public function new( x : Int, ?y : Int ) {
        this.x = x;
        this.y = (y == null) ? 0 : y; // "y" is optional
    }

Class Inheritance

When declared, it's possible that a class extends one class and implements several classes or interfaces. This means the class will inherit several types at the same time, and can be treated as such. For example :

    class D extends A implements B implements C {
    }

Every instance of D will have the type D but you will also be able to use it where an instance of type A, B or C is required. This means that every instance of D also has the types A , B and C.

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

Extends

When extending a class, your class inherits from all public and private non-static fields. You can then use them in your class as if they were declared here. You can also override a method by redefining it with the same number of arguments and types as its superclass. Your class can not inherit static fields.

When a method is overridden, then you can still access the superclass method using super :

    class B extends A {
        override function foo() : Int {
            return super.foo() + 1;
        }
    }

In your class constructor you can call the superclass constructor using also super :

    class B extends A {
        function new() {
            super(36,"");
        }
    }

Implements

When implementing a class or an interface, your class is required to implement all the fields declared or inherited by the class it implements, with the same type and name. However the field might already be inherited from a superclass. (Implementing a class, rather than an interface, is not supported for flash, c++ or java).

Interfaces

An Interface is an abstract type. It is declared using the interface keyword. By default, all interface fields are public. Interfaces cannot be instantiated.

    interface PointProto {
        var x : Int;
        var y : Int;
        function length() : Int;
    }

An interface can also extend one or several interfaces :

    interface PointMore extends PointProto {
        function distanceTo( p : PointProto ) : Float;
    } 

Helper Classes


In Haxe, it is possible to have more than one class definition per class file:
// both definitions in Foo.hx
class Foo { ... }
class FooHelper { ... }

This is fairly common in many object oriented languages such as Java. However, unlike other such languages, Haxe also allows for these internal helper classes to be publicly available outside of the main class. By importing the main class, the helper class becomes available:

// in Bar.hx
import Foo;
class Bar{
     var b:FooHelper;
}

The helper class can also be made accessible via an extended package declaration:

// in Bar.hx
class Bar{
     var b:Foo.FooHelper;
}

The use of public internal helper classes is typically not a recommended practice in most languages. Since helper class names do not correspond with their .hx file names, they can be harder to find in source trees.

HaXe lets you mark an internal helper class with the private keyword, in the same way that fields are marked:

// both definitions in Foo.hx
class Foo { ... }
private class FooHelper { ... }

This prevents the internal helper class from being accessed outside of the main class.

Unless there is a good reason for their use, consider placing each public class definition in its own .hx file, or make the internal class private, to prevent its definitions being included (and possibly causing a name conflict) when the main class is imported.

«« Type Inference - Type Parameters »»

version #20106, modified 2014-05-11 22:04:20 by Chax0