Hack types

4 minute read

The biggest difference between Hack and PHP is that PHP is using dynamic typing and Hack is statically typed. Java and C# is other languages that is statically typed. This means that the type on variables must be defined before runtime. Example of types are string, int, bool, array. There are even types like MyObject, Vector<int> and mixed. It is good practice to annotate all class variables, function parameters and function return types. There is no need to annotate local variables.

&lt;?hh
class Foo {
  public function bar (int $var): string {
    return &quot;Number: &quot;.$var;
  }
}

So why types?

I order to find bugs before runtime you need types. It is very hard to do a type check before run time on a dynamically typed language. You may rely on a function foobar() returning an array but sometimes it might return null instead of an empty array. Or maybe it returns a scalar instead of an array with one element. When you are using a static typed language the type checker (or complier for Java and C#) will find that foobar() may return null but has declared array as return value.

The type checker will make your code reliable. You fill find that the contract between classes is much more strict. If the return type is declared as array you know that it will return an array. With PHP you could only be sure that you would get an array and you would have to read the production logs to find out when it doesn’t.

To activate the type checker you need to start your hack file with <?hh instead of <?php. There are 3 modes of the type checker: strict, partial and decl. The default mode is partial. I’ve written another blog post about the modes and the differences.

Type casting

In PHP you may write

&lt;?php
class Foo {
  private $a=4711;   //$a is a int
  public function __contruct() {
    $this-&gt;a=&quot;foobar&quot;; // $a is a string
  }
}

That is not allowed in Hack:

&lt;?hh
class Foo {
  private int $a=4711;   //$a is a int
  public function __contruct() {
    //You cant assign a string to an int
    $this-&gt;a=&quot;foobar&quot;; // $a is a string
  }
}

If you want to change a type you may use type casing:

&lt;?hh
class Foo {
  private int $a=4711;
  private bool $b;
  private bool $c;
  public function __contruct() {
    //You cant assign a string to an int
    $this-&gt;b = (bool) $this-&gt;a;
    $this-&gt;c = (string) $this-&gt;a;
  }
}

Hack has chosen consistency over convenience when it comes to type aliasing. You may not use integer over int, Boolean over bool or double over float. This is because they want the code to be easier to read.

The “this” type

You may annotate with this when you return an instance of the class. Keep in mind that this could be an instance of a child class. This is a valid use of the this type:

&lt;?hh
class Foo {
  private int $x = 0;
  public function setX(int $var): this {
    $this-&gt;x=$var;
    return $this;
  }
}

You may not use the this annotation in the following situations. This is because Foo could be extended and $this is not the same type for the subclass as it is for the base class.

&lt;?hh
class Foo {
  //this is wrong
  public function newFoo(int $var): this {
    return new Foo();
  }
  //this is wrong
  public function newSelf(int $var): this {
    return new self();
  }
}

Do I really have to?

I said that Hack is statically typed. That is not true… It is gradually typed. This means that you may omit the type annotation if you like. But doing this the type checker will (of course) not be able to help you find type related bugs. I highly encourage you to always use type annotations.

Categories:

Updated:

Leave a Comment