1

HHVM 3.9 is not such a fan of ternary statements with named functions, even when passed through fun(), but ≥3.10 is totally fine with them. It seems as though this is one of few cases, however, because 3.9 does accept named functions returned from concrete functions, as well as accepting named functions passed into other functions (3v4l):

<?hh
echo ((() ==> fun('strlen'))())('Hello'); // 5
echo (($f, $v) ==> $f($v))(strlen, 'Hello'); // 5 + Notice: Use of undefined constant strlen - assumed 'strlen'
echo (true ? strlen : intval)('100'); // Fatal error: syntax error, unexpected '(', expecting ',' or ';' on line 3

What changed between 3.9 and 3.10? Are there any cases in HHVM ≥3.10 where named functions cannot be referenced and used this way?

concat
  • 3,107
  • 16
  • 30

1 Answers1

1

First, when writing Hack, don't write your code at toplevel; the hh_client typechecker can't check anything at toplevel. And 3v4l doesn't run the typechecker at all, you need to run it locally.

That said, no, Hack doesn't really have first-class functions. Most of its behaviour here it inherited from PHP, which also doesn't have them. Back when I was working on the Hack team, we tossed around a lot of ideas for adding them to the language; it's an obvious addition and need. But the need was never quite strong enough such that we sat down and actually worked out the details for both the type system and runtime implications; in particular, how to work out some of the scoping issues that the current callables have. Anonymous functions fill out enough of the need, especially with Hack's short lambda syntax, that there was always something more pressing to deal with.

So Hack just has PHP's normal callable forms; fun is one of a few special functions which give information to the typechecker that the string you specified actually represents a function so the typechecker can do proper type analysis. But at the end of the day, fun just boils down to the usual PHP callable forms with a bit of extra magic in the typechecker.

As to the behaviour you indicate in your 3v4l link. Using strlen and intval like that would cause a type error in Hack, since those are syntactically constants but constants with those names don't exist since Hack doesn't have first-class functions -- or it would if the code weren't at toplevel and you were running the typechecker. As to why it causes a parse error in HHVM 3.9 (which masks the "invalid constant" errors you see in 3.10), I'm not 100% sure. Judging from this example which works in PHP7 and HHVM 3.10, but not PHP5 and HHVM 3.9, my guess it is a PHP7 feature that is backwards compatible and so is always enabled in HHVM.

Josh Watzman
  • 7,060
  • 1
  • 18
  • 26
  • Ah, so this is more of a question of what _PHP7_ supports wrt named functions. I'm curious as to why the `Notice...undefined constant` is suppressed by `fun` if it "just boils down to the usual PHP callable forms", but it's a minor detail I suspect. To clarify: outside of type errors, there are no cases where `fun('foo')` and `foo` are interpreted differently, right? – concat May 14 '16 at 18:33
  • The type errors are the entire point; they are emphatically not the same in the typechecker. However, [at runtime, yes](https://github.com/facebook/hhvm/blob/cc7f35361e5dfc934631e1e19e2f2b9f66890391/hphp/system/php/lang/fun.ns.php#L31-L67). EDIT: keep in mind the comments in the code I linked have code at toplevel and as such are wrong, but [the normal public docs](https://docs.hhvm.com/hack/callables/special-functions) are right. – Josh Watzman May 15 '16 at 08:52