Hack: a new programming language for HHVM
Today we’re releasing Hack, a programming language we developed for HHVM that interoperates seamlessly with PHP. Hack reconciles the fast development cycle of PHP with the discipline provided by static typing, while adding many features commonly found in other modern programming languages.
We have deployed Hack at Facebook and it has been a great success. Over the last year, we have migrated nearly our entire PHP codebase to Hack, thanks to both organic adoption and a number of homegrown refactoring tools.
Every PHP programmer is familiar with day-to-day tasks that can be tricky or cumbersome. The code above is a great example of a common mistake where a method could unexpectedly be called on a null object, causing an error that wouldn’t be caught until runtime. Another example is a complex API, where developers may have a solid understanding of its semantics but still spend time looking up mundane method names in documentation.
At Facebook scale — with thousands of engineers shipping new code twice a day — slowdowns like these are even more problematic. Before Hack, we had a simple language with a quick feedback loop — but how could we mitigate the sorts of problems described above? Could early error detection coexist with rapid iteration, all while preserving our investment in PHP? Could improved code analysis and introspection help make developers more productive with tools like auto-complete?
Traditionally, dynamically typed languages allow for rapid development but sacrifice the ability to catch errors early and introspect code quickly, particularly on larger codebases. Conversely, statically typed languages provide more of a safety net, but often at the cost of quick iteration. We believed there had to be a sweet spot.
Thus, Hack was born. We believe that it offers the best of both dynamically typed and statically typed languages, and that it will be valuable to projects of all sizes.
The Hack language
Hack has deep roots in PHP. In fact, most PHP files are already valid Hack files. We made a conscious choice not to support a handful of deprecated functions and features that were incompatible with static typing (e.g. “variable variables” and the extract() function). We have also added many new features that we believe will help make developers more productive.
Our principal addition is static typing. We have developed a system to annotate function signatures and class members with type information; our type checking algorithm (the “type checker”) infers the rest. Type checking is incremental, such that even within a single file some code can be converted to Hack while the rest remains dynamically typed. Technically speaking, Hack is a “gradually typed” language: dynamically typed code interoperates seamlessly with statically typed code.
Within Hack’s type system, we have introduced several features such as generics, nullable types, type aliasing, and constraints on type parameters. These new language features are unobtrusive, so the code you write with Hack will still look and feel like the dynamic language to which PHP programmers are accustomed.
However, Hack adds additional features beyond static type checking, including Collections, lambda expressions, and run-time enforcement of return types and parameter types.
Collections provide a clean, type-safe alternative to PHP arrays. We designed them specifically to work well with static typing and generics. The Collections API offers many classic higher-order functions such as map() and filter() to facilitate functional programming styles.
Lambda expressions give a concise syntax for creating closures. While PHP has closures, it requires the programmer to explicitly name the variables they need to use from enclosing scopes. With Hack’s lambda expressions, we automatically infer these uses, saving you needless work. Lambda expressions make it more convenient to take full advantage of the Collections API.
Run-time enforcement of return types and parameter types (including scalar types like int and string) provides safety beyond what can be checked statically while type annotations are being gradually added to a codebase. Run-time enforcement helps programmers detect and diagnose certain kinds of problems more easily, and it helps HHVM’s JIT produce more efficient code by making it safe to trust type annotations for optimization purposes.
Instantaneous type checking
During development, a PHP programmer typically goes back and forth rapidly between the source code and the browser. Engineers can iterate as quickly as they need, testing and tuning an experience until it’s perfect.
Traditionally, a type checker would disrupt this feedback loop as it takes time to analyze the source code. We didn’t want to slow the PHP workflow, so we came up with a new approach to reconcile instantaneous feedback with type safety.
Our solution was to architect the type checker as a local server that watches the filesystem. The server keeps all information about the source code in memory and automatically updates itself when a file changes on disk. This approach has paid off: the type checker typically runs in LESS than 200 milliseconds and rarely takes more than a second, making it easy to integrate into the development workflow without introducing a noticeable delay.
Hack’s type safety and refactoring benefits grow the more it is used within a codebase. Understanding that it would be difficult for some code to be completely transitioned to Hack right away, it was important to us that Hack be developed such that it can coexist directly with other PHP files as it is being introduced incrementally.
The rest of the conversion process, such as adding type annotations and using new language features, can be done as appropriate for the codebase. For example, a type annotation can be added for one function but left off another function, even in the same file. If a function parameter or class member does not have an explicit type annotation, the type checker considers its type to be dynamic, and it does not check the type of that value.
Within Facebook, we found that our engineers appreciated Hack enough that they started converting the majority of their own code voluntarily. With millions of lines of code in our tree, we also wanted some form of automation, so we built and use a number of code modification tools to assist the process (which we are releasing as part of Hack).
Don’t worry, your PHP is safe!
HHVM is still a PHP runtime, and we intend to keep it that way. In fact, we are working hard to reach parity with PHP-5. One of HHVM’s top priorities is to run unmodified PHP-5 source code, both for the community and because we rely on third-party PHP libraries internally.
Have fun with Hack!
We are delighted to open-source both Hack and the tools you can use to automatically convert your codebase. This is just the first step, and we are dedicated to continuing to evolve this software to make development even easier for both our own engineers and the broader community. Hack’s value is not limited to big projects: with type information, good error messages, and fast feedback, small codebases can reap the benefits of Hack as well.
Next month, we will also introduce the language at the Hack Developer Day on the Facebook campus in Menlo Park, and we hope to see you there in person or online.
We would love to have your feedback on our work so far, and welcome you all to participate in the HHVM and Hack community.
There are many people who have contributed to the development of Hack.
The core Hack team consists of Julien Verlaguet, Joel Beales, Eugene Letuchy, Gabriel Levi, Joel Marcey, Erik Meijer, Alok Menghrajani, Bryan O’Sullivan, Drew Paroski, James Pearce, Joel Pobar, and Joshua Van Dyke Watzman.
A special thanks goes to our early community adopters for providing valuable feedback to make the language better: James Miller, Simon Welsh, Nils Adermann, Fabien Potencier, and Alexander Mols.
Hack is written primarily in OCaml. We would like to thank the Gallium team (INRIA) for the development of the OCaml language, and the Ocsigen team (CNRS – University of Paris Diderot – INRIA) for the development of the js of ocaml part of Ocsigen.
And, of course, thank you to everyone else who has helped make Hack the language it is today. The list is too exhaustive for a blog post, but you know who you are.
Hack reconciles the fast development cycle of a dynamically typed language with the discipline provided by static typing, while adding many features commonly found in other modern programming languages.
Hack provides instantaneous type checking by incrementally checking your files as you edit them. It typically runs in LESS than 200 milliseconds, making it easy to integrate into your development workflow without introducing a noticeable delay.
Built for HHVM
Hack is built specifically for HHVM, a high performance runtime for your Hack applications.