Hack programming language, the PHP apocalypse?
Introduction
About a month ago, Facebook released the Hack programming language.
Since then, apocalyptic articles related to this language and to how it will replace PHP have appeared everywhere. The title of this article was inspired by “Will Hack Kill PHP?“.
What is even more strange to me is that it was followed by a wave of negative assessments related to PHP, apparently Hack “fixes” the previously mentioned language. In my opinion, the language has to be “broken” in the first place to be “fixed”.
Off-course PHP has many drawbacks, like any other programming language, but there must be a good reason why it is the most popular language for the Web. After all, Facebook used it for a long time, and now it is not replaced, they are improving it… aren’t they?
One thing is for certain, it is probably one of the least inspired names. When you search for “Facebook hack” you will find anything else but this programming language…
About Hack
Hack is running on HHVM. HHVM is Facebook’s try to optimize the PHP language with Just In Time complication, the latest approach in optimization of the language. Basically, Facebook is trying to reduce their costs by optimizing the language interpreter, and now with a new language all together. After all, if we think about Facebook’s infrastructure, it’s normal for them to do this, even a relatively minor optimization will lead to a consistent cost reduction.
Initially, I thought it was an “improved” version, but it seems like it is another language altogether, basically it’s a PHP with something extra!
A small tutorial of the language is at: http://hacklang.org/tutorial/.
The tutorial doesn’t cover all the features of the language, more details are at: http://docs.hhvm.com/manual/en/hacklangref.php.
Practically, about all the features that differ in Hack from PHP are optional. You can almost write PHP and it will work. Contrarily to expectations, not even specifying the type of the input/output of the variables is not required.
Because after all it’s a different programming language altogether, I’m not going to go into much details on all the new features. That is more the purpose of a book, not an article.
I only want to point out a few features that I found interesting.
Strangely, at least at the begging, at runtime the type of the result, even though it is sent, is not necessarily interpreted.
Let’s take an example:
1<?hh
2
3function a($a): void {
4 return true;
5}
6
7echo a('a');
This example will have the output… 1.
Basically, at runtime only the input type is checked, not the output one.
To run the Typechecker in the current directory, an empty file must be added:
1$ touch .hhconfig
Then run:
1$ hh_client
As you can see, the data types are checked in a separate step beside runtime.
At the manual execution of the Typechecker, it will find all the inconstancies. The purpose is for it to identify the problems before the runtime, for instance when you edit a file, not when the app is actually running.
The Typechecker output is:
1../test.php:4:9,12: Invalid return type
2../test.php:3:17,20: This is void
3../test.php:4:9,12: It is incompatible with a bool
Unfortunately, there is still a lot of work to be done with this feature. If we try to validate only at runtime, using “type hinting” like in PHP, the function becomes:
1function a(int $a): void {
2 return true;
3}
4
5echo a('a');
The output of the Typechecker is not changed, but upon execution the result will be:
1Fatal error: Argument 1 passed to a() must be an instance of int, string given in ../test2.php on line 5
Basically, the Typechecker is doing what the type hinting is not and the the latter is now also receiving scalar type arguments.
Even if the only change was to add scalar arguments checking, I would have still considered it an important improvement.
It is a syntax that is more popular with the functional languages.
An example:
1<?hh
2
3$sqr = $x ==> $x * $x;
4
5echo $sqr(5) . PHP_EOL;
Off course the result will be 25.
I find it a very interesting and clear way to represent small logic.
In the new syntax, a function can also return another function:
1$add = $x ==> $y ==> $x + $y;
2
3$result = $add(1);
4
5echo $result(2) . PHP_EOL;
The result will be 3.
If a variable from inside a lambda expression doesn’t exist in the scope of the function definition, then it will be retrieved from the environment in which the expression was declared:
1// variable in the current scope
2$z = 5;
3
4$addZ = $x ==> $x + $z;
5// change the variable in from current scope
6$z = 6;
7
8// perform the add
9echo $addZ(1) . PHP_EOL;
The result will be… 6!
The equivalent in PHP is:
1$addZ = function ($x) use ($z) {
2 return $x + $z;
3}
The value of $z will be retrieved for the environment where the function was defined, not as a reference to the variable.
Off course that’s not the case when the variable from the outside of the function is an object, in this case it will be passed by reference:
1<?hh
2
3class a {
4 public function __construct(public string $x) {}
5 public function __toString() {
6 return $this->x;
7 }
8}
9
10// variable in the current scope
11$z = new a('Claudiu');
12
13$addZ = $x ==> $x . ' ' . $z . '!';
14
15// change the variable that will be used for concatenation
16$z->x = 'World';
17
18// run the concatenation
19echo $addZ('Hello') . PHP_EOL;
The output will be:
1Hello World!
Again, a syntax more popular with the functional programming languages. The purpose is to validate a more specific type of structure than an array.
The reason is very good, validate simple data structures. The structures that are getting checked should contain the elements defined in the shape.
1<?hh
2
3// defining a structure
4newtype Circle = shape('radius' => int);
5
6// a function that will is using the type of the structure above
7function areaCircle(Circle $param) {
8 return M_PI * $param['radius'] * $param['radius'];
9}
10
11// a series of shapes that are using the structure
12$circle = shape('radius' => 10);
13$cilinder = shape('radius' => 10, 'height' => 15);
14
15// a structure that should not work pass as Circle
16$sqr = shape('side' => 10);
17
18echo areaCircle($circle) . PHP_EOL;
19echo areaCircle($cilinder) . PHP_EOL;
20echo areaCircle($sqr) . PHP_EOL;
The output is:
1314.15926535898
2314.15926535898
3
4Notice: Undefined index: radius in /home/brand/test.hh on line 6
5
6Notice: Undefined index: radius in /home/brand/test.hh on line 6
70
A little disappointing, I was hoping that the parameter that doesn’t match the structure will trigger an error, but it passes.
Not even the Typechecker finds anything wrong.
The intention is very good, now we just have to wait for the working version.
Conclusion
Probably Hack will influence PHP, which is normal in the end, it happens all the time with programming languages.
Will it replace PHP? I don’t think so, probably there will be a lot of adopters for cost reduction or a better structuring of the code.
It is not very kely for this language to be successful in the following years other than for projects of medium and large sizes. For small projects usually shared hosting is used, and this generally doesn’t have the latest PHP version, it is even less likely for it to have the latest HHVM. This is probably one of the least interesting arguments, but in the end most of the websites on the web are of small and very small size, they make up the “mass”.
An easier approach to optimization is to only use HHVM. In theory, you don’t have to change anything and the results should be visible immediately! Practically HHVM is not 100% compatible with Zend Engine, but this problem is getting less of an issue with each version. One of the priorities for HHVM is to interpret the code the same way Zend Engine does, but to be much more efficient!