The Hack Standard Library: v1.0
Today, we’re releasing the first stable version of the Hack Standard Library. The Hack Standard Library addresses several issues:
- existing collection functionality (such as filtering and mapping) either returns PHP arrays, or Hack Collection objects; we needed support for the new
dict
,keyset
, andvec
types (Hack Arrays). - we want Hack to have a standard library that is internally consistent.
- many PHP builtins can not be typed in Hack, due to intentional restrictions in the type system: parameters that accept multiple types (e.g.
string | object
) can only be typed as takingmixed
, and while nullable types are supported (?sometype
), falseable types aren’t - so anything that returnssometype | false
must be typed as returningmixed
in Hack. - we wanted users to be able to add functionality in a manner consistent with the standard library; this wasn’t possible with Hack Collections where the functionality was defined as methods on builtin objects - any extensions needed to be committed to HHVM.
Since v0.1, our priority has been finding and addressing inconsistencies in our API; we’re grateful to our community for helping us with this, and are proud to release v1.0 without any known issues.
Getting started
You’ll need:
After installing HHVM and Composer, the next step is configuring hhvm-autoload via an hh_autoload.json
file in your project root; full information on options is in the readme, however this will be a good starting point for most projects:
1
2
3
4
5
6
7
8
9
{
"roots": [
"src/"
],
"devRoots": [
"tests/"
],
"devFailureHandler": "Facebook\\AutoloadMap\\HHClientFallbackHandler"
}
With this configuration:
- the contents of
src/
,tests/
, andvendor/
will usually be autoloaded; vendor/ library autoloading is implicit, and handled according to each dependency’shh_autoload.json
orcomposer.json
. - if
--no-dev
is passed to composer,tests/
will not be autoloaded. - if
--no-dev
is not passed, and autoloading fails, the autoloader will ask the Hack server where to find the required definition. This usually means that you can add, rename, modify, and delete any Hack autoloadable without having to rebuild the map. Some changes to PHP code will still require runninghhvm composer dump
orvendor/bin/hh-autoload
Once you’ve created the configuration file, you’ll need to install hhvm-autoload and the HSL:
1
hhvm composer require hhvm/hhvm-autoload hhvm/hsl
Finally, you’ll need to use the new autoloader - this is similar to using Composer’s autoloader: include vendor/hh_autoload.php
in your entrypoints, instead of vendor/autoload.php
. If you are using PHPUnit, you will also need to include this from your bootstrap file; if you don’t already have a bootstrap file, you can directly set vendor/hh_autoload.php
as your bootstrap file.
Container functions
There are four main groups of functions for interacting with containers:
HH\Lib\Dict
: functions that return adict
.HH\Lib\Keyset
: functions that return akeyset
.HH\Lib\Vec
: functions that return avec
.HH\Lib\C
: functions that operate on containers, but do not return a container.
For example, mapping and filtering functions exist in each of the HH\Lib\{Dict, Keyset, Vec}
namespaces, however functions such as contains()
, contains_key()
, count()
, and reduce()
are in the HH\Lib\C
namespace.
We recommend using Hack’s use namespace
feature for the HSL, as this allows aliasing the namespaces without affecting the types: while Hack considers names to be case sensitive (e.g. that vec
and Vec
do not conflict), the runtime is currently case-insensitive for PHP compatibility.
Operations are generally combined using the pipe operator:
1
2
3
4
5
6
7
8
9
<?hh
use namespace HH\Lib\{C, Vec};
function square_then_sum(vec<int> $in): int {
return $in
|> Vec\map($$, $x ==> $x * $x)
|> C\reduce($$, ($acc, $x) ==> $acc + $x, 0);
}
The HSL also contains functions for common async operations on containers, such as:
HH\Lib\{Dict, Keyset, Vec}\from_async($in)
: create a(dict|keyset|vec)<T>
from a(Traversable|KeyedTraverable)<Awaitable<T>>
.HH\Lib\{Dict, Keyset, Vec}\filter_async($in, (function(Tv):Awaitable<bool>) $async_predicate)
: returns adict|keyset|vec
containing the values from$in
where awaiting the predicate returns true.HH\Lib\{Dict, Keyset, Vec}\map_async($in, (function(Tv1):Awaitable<Tv2>) $mapper)
: returns adict|keyset|vec
from$in
, where the values have been replaced with the result of awaiting the specified mapping function.
Additional functions
The HSL also includes functions for common math and string operations, in the HH\Lib\Math
and HH\Lib\Str
namespaces. We expect to both increase the functionality in these namespaces, and start covering additional areas in the future, such as regular expressions.
What’s next?
In the short term, our priorities are to improve the documentation, and to use the HSL to make sure that our other libraries have full support for the dict
/keyset
/vec
types.
This is just the beginning: now that we have a solid starting point, we’ll be adding functionality to the HSL, with the additional goal of eventually removing the need for Hack software to use PHP builtins directly - and once ‘Pure Hack’ projects are a practical reality, we can explore the possibility of removing the PHP builtins from HHVM itself.