Unsupported: References

A widely used feature of PHP, references (&), is not supported in Hack. And while this can be especially painful for existing code wanting to convert to Hack's strict mode, there is a very sound reason for not supporting them. The typechecker cannot do proper analysis of code that have references. The typechecker depends on a fundamental set of rules in order to make its decisions (e.g., type inference being local to a function). And references violate many of those rules.

The key example of this violation is that a reference passed to a function is modifiable at the caller site, and the typechecker cannot accurately analyze what may or may not happen at the callee in order to bridge the two.

Partial mode

You can use references in partial mode and decl mode, but they are not typechecked. The typechecker pretends that references don't exist: the & is invisible to the typechecker in these modes. So use them at your own risk, because with more complicated reference usage, it is easy to cause type errors the typechecker can't see.

<?hh

namespace Hack\UserDocumentation\Unsupported\References\Examples\Partial;

class A {
  public int $x;
  public function __construct(int $x) {
    $this->x = $x;
  }
  public function setX(int& $x): void {
    $this->x = $x;
  }
}

function foo(int& $x): void {
  $x++;
  $y = $x;
  $a = new A($x);
  $a->setX($y);
}

function bar(int& $x): void {
  $y = $x;
  $y = 5;
  $x = $y;
  foo($x);
}

function baz(): int {
  $x = 4;
  bar($x);
  return $x;
}

var_dump(baz()); // No typechecker errors. HHVM returns int(6)
Output
int(6)

There are no errors reported by the typechecker with this code. However, what does the call to baz() return from HHVM? Well notice that none of the functions except baz(), return an int. They return void. Without references, you know that $x would be 4 at the end of the call to baz(). However, through the convoluted web of all the references, it actually returns 6 here.

Strict mode

The typechecker issues an error in strict mode anytime you try to use a reference.

<?hh // strict

namespace Hack\UserDocumentation\Unsupported\References\Examples\Strict;

class A {
  public int $x;
  public function __construct(int $x) {
    $this->x = $x;
  }
  public function setX(int& $x): void {
    $this->x = $x;
  }
}

function foo(int& $x): void {
  $x++;
  $y = $x;
  $a = new A($x);
  $a->setX($y);
}

function bar(int& $x): void {
  $y = $x;
  $y = 5;
  $x = $y;
  foo($x);
}

function baz(): int {
  $x = 4;
  bar($x);
  return $x;
}

var_dump(baz()); // Typechecker errors. HHVM returns int(6)
Output
int(6)