Search code examples
hhvmhacklang

How to properly type a generator function in Hack


I'm playing around with Hack for a bit and tried to create a generator function using the yield keyword. The documentation states that the return type of such a function should be the Continuation interface. However, when running hh_client on the source code example of the generator function I get the following output:

./test.php:4:3,7: Invalid yield (Typing[4110])
./test.php:3:17,28: This is an object of type Continuation
./test.php:4:3,7: It is incompatible with an object of type Generator (result of function with 'yield' in the body)

This is test.php:

<?hh

function gen(): Generator<int> {
  yield 1;
  yield 2;
  yield 3;
}

function foo(): void {
  foreach (gen() as $x) {
    echo $x, "\n";
  }
}

foo();

Changing the result type to Generator gives even more warnings. What is the correct way of typing a generator function?


Solution

  • Any mention of Continuation in the docs is outdated and wrong. There's an open issue about it.

    The correct type is Generator<Tk, Tv, Ts> -- there are actually three type parameters there. Here's an example of what they mean:

    $r = yield $k => $v;
    

    The type of that generator is Generator<Tk, Tv, Ts>, where Tk is the type of $k, Tv is the type of $v, and Ts is the type of $r.

    For your code, this should work:

    function gen(): Generator<int, int, void> {
      yield 1;
      yield 2;
      yield 3;
    }
    

    The first int because there is implicitly an integer key; the second int because you are yielding ints, and the void since you don't care what values are sent into the generator.