Using Hack language & Prismic.io

Written by Sébastien Renault in Engineering on June 19,2014

As you may already know, Facebook released last March, a new programming language for the HipHop Virtual Machine named Hack. Hack is what Typescript is for Javascript: a superset of a primary language, PHP. What does it mean ? It means that PHP is Hack compliant and Hack brings some new features to PHP. This results in most of the existing PHP codebase remaining usable in Hack.

Of course, the principal addition of Hack to PHP is the type safety! Because we can mix statically-typed code and dynamically-typed code together, we say that Hack is a gradually typed language. This is very handy when you want, like I did with the prismic.io PHP kit, to convert a PHP project to Hack incrementally.

But this is not just about adding type safety to PHP, Hack also brings modern features like generics, nullable types, type aliasing, generators, mixins, true lambda expression, etc. Along with these new features, Hack provides a clean type-safe way to deal with PHP arrays through the Collections API. Behind this API, there are some interesting mutable and immutable data structures like Vector, Map, Pair, Tuple.

From PHP kit to Hack kit

As I said earlier, I didn’t start the Hack prismic.io kit from scratch. I started from the existing PHP kit and slowly started replacing <?php tags by <?hh tags, adding some type annotations, and rewriting some PHP code to use immutable structure like ImmMap and ImmVector. Because Hack is compliant with PHP, after each modification, I was able to relaunch PHP unit tests and see if it doesn’t break anything.
If you are a developer who already uses the PHP kit, it will be very straightforward to use the Hack kit. Main differences occured when some functions initially returned PHP plain objects and now return ImmMap.

Using the Hack kit to create the Hack starter project

About the Hack plain starter project, I decided not to convert it from the existing PHP plain starter project, but to directly rewrite it from scratch, mainly because in Hack, we can’t mix Hack code and HTML like we could in PHP (anyway, xhp is a preferable way to deal with HTML). Instead, to organise the code, I tried to follow the hack-example-site code provided by the Hack team.

For the rest of the blog post, I will show you how to use the Hack kit through the Hack starter project by implementing some of its features. Let's dive into the first one: paginate all documents of a repository. This is very basic:

The corresponding code that build and execute the query looks like this:

$ctx->getApi()
->forms()
->at('everything')
->ref($ctx->getRef())
->pageSize(10)
->page($page)
->submit();

The code is pretty easy to understand. The “$ctx” variable is built on each request using a helper function that is offered by the starter project. Basically, it brings together the current HTTP parameters and what we call the “Api”. The “Api” is needed before starting to query any document. It can be fetched on the following endpoint: http://domain.prismic.io/api. It returns important information, like: what is the current master ref ? what are available releases ? what are available forms (collections) ? and more.

prismic.io API's restful approach saves you from building your own URLs to query documents. The code above gets the “Api”, selects the “everything” form (doesn't narrow to a particular collection), points out the release reference (do I want to fetch currently published documents or scheduled documents?), sets pagination parameters (documents per page, page number), and finally performs the query. That is all.

Let's move on to the second feature of the starter project: displaying a specific document. The HTML representation of the document is just thrown into the web page without any styling:

Building the query to get one document looks like:

$ctx->getApi()
->forms()
->at('everything')
->query('[[:d = at(document.id, "'. $id .'")]]')
->ref($ctx->getRef())
->submit()
->getResults()
->get(0);

A document is identified with an id that we got, say, when we fetched documents on the listing page. Compared to the previous code, we are still searching over all documents (by selecting the “everything” form), but now we are supplying an additional parameter that is the query. The query allows us to express documents we want to retrieve, by defining some facts that describe them (called predicates). For our case, we want to query one document by its identifier (in the "everything" form).

Last word

I want to conclude this article with my feelings about Hack, based on my own experience of writing the Hack starter project. Generally, it made me feel comfortable for several reasons. The Hack type checker did get my confidence. The final code seems more readable and safer to me. Combining Hack language & xhp together results in a great tool to master web applications, including ones using prismic.io for their content management.

Sébastien Renault

Core developer and architect.