3.6 Type Inference

The effects of type inference have been seen throughout this document and will continue to be important. A simple example shows type inference at work:

class Main {
  public static function main() {
    var x = null;
    $type(x); // Unknown<0>
    x = "foo";
    $type(x); // String
  }
}

The special construct $type was previously mentioned in order to simplify the explanation of the Function Type type, so let us now introduce it officially:

Define: $type

$type is a compile-time mechanism being called like a function, with a single argument. The compiler evaluates the argument expression and then outputs the type of that expression.

In the example above, the first $type prints Unknown<0>. This is a monomorph, a type that is not yet known. The next line x = "foo" assigns a String literal to x, which causes the unification of the monomorph with String. We then see that the type of x indeed has changed to String.

Whenever a type other than Dynamic is unified with a monomorph, that monomorph becomes that type: it morphs into that type. Therefore it cannot morph into a different type afterwards, a property expressed in the mono part of its name.

Following the rules of unification, type inference can occur in compound types:

class Main {
  public static function main() {
    var x = [];
    $type(x); // Array<Unknown<0>>
    x.push("foo");
    $type(x); // Array<String>
  }
}

Variable x is first initialized to an empty Array. At this point we can tell that the type of x is an array, but we do not yet know the type of the array elements. Consequentially, the type of x is Array<Unknown<0>>. It is only after pushing a String onto the array that we know the type to be Array<String>.