davesmithhayes.com

Software, audio, and other musings.

Getting into Hack

June 16, 2016

I’m going to start this post with an opinion: Hack is a terrible name. Not only that, it runs on the HHVM, which stands for the Hip Hop Virtual Machine, which I also believe is a terrible name. Thankfully bad names don’t equate to bad platforms.

I’m a big fan of PHP7 and all the neat stuff that they have introduced to the language. Most specifically I like like the scalar type hinting. Knowing exactly what goes in, and what can come out of a function really helps other developers understand its purpose. I’ve dealt with large codebases that have had me stack tracing entire requests and response calls just to get a slight idea what the hell was going on.

Hack has been described as PHP with strict typing, but I think its much more than that.

If you come from the modern [sic] PHP world, then you know all about Composer and PSR-4 (or PSR-1, either way, some form of autoloading) and decent package management. When I first started writing some basic Hack scripts, they were single file Hello World!’s and ran directly from either the HHVM built in server or as a script from the HHVM itself. I had an idea for a small microframework and started to work. I don’t know why I assumed this, but I figured Hack would have its own autoloading techniques. Little did I know, I could just use Composer.

Note that Bastard is far from ready for anything, I’ve just been playing around trying to make something useful with Hack and figured this would be a good idea. If you want to help me out with its development, feel free to see me an email!

The Set Up

I just grabbed the HHVM from APT because its probably going to be stable, and it will work for my purpose of just testing stuff. If I was gearing up for production, I’d probably grab the latest packages straight from Facebook themselves.

$ sudo apt install -y hhvm

I don’t think I needed to even show you that, but that’s what I did.

If you’re like me, you linked the composer.phar package to your path so you could use it anywhere in the system. However doing this makes it run with PHP locally every single time you call the phar. So I wrote a small script (I’m a huge fan of small scripts, if you couldn’t tell) that will actually call the phar from HHVM.

#!/usr/bin/env bash
hhvm /usr/local/bin/composer $@

Basically passing all the arguments you normally would for Composer into the script. I named the file hcomposer.sh and proceeded to link it into my path. Composer is smart enough to know if you’re running PHP or Hack and that is absolutely gorgeous. Good on them.

Autoloading

So doing some research through the Hack documentation, I found a neat function called HH\autoload_set_paths() which I assumed worked a lot like the spl_autoload_register() method in PHP. However I couldn’t seem to get it to work properly and ended up writing like 8 lines of class names and directory paths. This didn’t feel like autoloading at all.

So I took to the streets to see how other people had structured their Hack projects. To my surprise, you can set the autoloading up within your composer.json file itself. This is fantastic! “I bet it even lets me do PSR-4” I think to myself. Seeing as the directories were already set up in a PSR-4 fashion (old habits die hard) I figured I’d just give it a shot.

{
    "autoload": {
        "psr-4": {
            "Bastard\\": "src/"
        }
    }
}

I also made sure that Bastard would only run on the HHVM.

$ hcomposer require hhvm
$ hcomposer update

Again, if you’re familiar with PHP you should see your good friend vendor in the root of the project directory. In there you should see an autoload file that will autoload all your awesome Hack classes. PSR-4 works with Hack.

File Extensions

So the kicker with Hack is that its still basically PHP. If you are writing plain old Hack classes and want the type checker (hh_client) to be strict on you about strict types, every file should start like this:

<?hh // strict

And have the .hh file extension. The extension isn’t necessary as you can still use .php but what’s the point if you’re really writing Hack? You know what I mean?

The main entry point of a Hack application should actually be a .php file extension called index.php. At least, that’s what I did with Bastard. The HHVM in server mode wont actually server an index.hh which I thought was weird, but what ever, I’m like totally over it (not really).

Running the Server

So far I have no plans on testing Bastard for production. At least not yet. For now I’ll use the built in HHVM server and when I get around to moving towards production environments, I’ll probably blog about the route I took. In the root directory of the project, I can run the server very easily, much like the PHP development server.

$ hhvm -m server -p 8888

So, that was easy.

Types!

Types are the best part of Hack I think. Not just the fact that while running with // strict you need to set return and parameter types for everything, but because Hack is really smart about when attributes are nullable or not and it will yell at you for not assigning values.

<?hh // strict

class Example
{
    private ?Map<string, string> $headers;
}

The above example has a private Map that can be null. We can tell because the type is prefixed with a question mark. Now if I try and do something like the following, the typechecker complains:

<?hh // strict

class Example
{
    private Map<string, string> $headers;
}

Because its not a nullable type, and it is currently set to a null value. But as I mentioned, Hack’s typechecker is actually smart. You can construct the Example class and pass it a Map<string, string> or you can initialize the variable inside the constructor with a default value and the typechecker is happy.

<?hh // strict

class Example
{
    private Map<string, string> $headers;

    public function __construct(Map<string, string> $headers)
    {
        $this->headers = $headers;
    }
}

Or:

<?hh // strict

class Example
{
    private Map<string, string> $headers;

    public function __construct()
    {
        $this->headers = Map{ 'key' => 'value' };
    }
}

So if you’re coming from PHP and you want to be able to set default values, you have to format your method’s a little differently. We’re used to assigning a default value right in the method’s parameters, but here we declare a nullable type, check if its passed null, and set a default value.

<?hh // strict

class Example
{
    private Map<string, string> $headers;

    public function __construct(?Map<string, string> $headers)
    {
        if (is_null($headers)) {
            $headers = Map{ 'key' => 'value' };
        }

        $this->headers = $headers;
    }
}

It has actually come to my attention, reading more Hack code from Facebook that you can still add defaults into the parameters of a method’s signature.

<?hh // strict

class Example
{
    private ?Map<string, string> $headers;

    public function __construct(?Map<string, string> $headers = null)
    {
        $this->headers = $headers;
    }
}

But of course this is only valid with a nullable type.

Conclusion

I am only a few days into writing Hack for something that could be useful one day, and I absolutely love it. I expect to work more and more with it, get more involved with the little community that exists out there, and help push it forward. Its a great language with great potential. Its already really easy to move into given my experience and fluency with PHP.

I highly recommend every PHP developer build something with Hack. Like right now. Do it.

To Top