Types: Generic Types

Hack contains a mechanism to define generic—that is, type-less—classes, interfaces, and traits, and to create type-specific instances of them via type parameters.

Consider the following example in which Stack is a generic class having one type parameter, T, and that implements a stack:

<?hh // strict

namespace Hack\UserDocumentation\Types\Generics\Examples\Stk;

class StackUnderflowException extends \Exception {}

class Stack<T> {
  private vec<T> $stack;
  private int $stackPtr;

  public function __construct() {
    $this->stackPtr = 0;
    $this->stack = vec[];
  }

  public function push(T $value): void {
    $this->stack[$this->stackPtr++] = $value;
  }

  public function pop(): T {
    if ($this->stackPtr > 0) {
      return $this->stack[--$this->stackPtr];
    } else {
      throw new StackUnderflowException();
    }
  }
}

As shown, the type parameter T (specified in Stack<T>) is used as a placeholder in the declaration of the instance property $stack, as the parameter type of the instance method push, and as the return type of the instance method pop. Note that although push and pop use the type parameter, they are not themselves generic methods.

<?hh // strict

namespace Hack\UserDocumentation\Types\Generics\Examples\UseStack;

require_once('Stack.inc.php');

function use_int_stack(
  \Hack\UserDocumentation\Types\Generics\Examples\Stk\Stack<int> $stInt,
): void {
  $stInt->push(10);
  $stInt->push(20);
  $stInt->push(30);
  echo 'pop => '.$stInt->pop()."\n";
}

Assuming we construct an instance for a Stack of ints, we can pass that to function use_int_stack, which can push values onto, and pop values off, that stack, as shown. And in the same or different programs, we can have stacks of string, stacks of ?(int, float), stacks of Employee, and so on, without have to write type-specific code for each kind of stack.

For more information, see generic types overview.