Attributes in Hack

First there where PHP annotations

The introduction of PHP style annotation by (mis)using comments always felt like a bad idea for me. Maybe because I think a comment cannot have any meaning beside some meaningful information for a developer or a documenting system that parses the comments to extract the information. But other than it should be possible to remove all comments without changing the behaviour of a progam.

So a comment should be structured in a proper way but should not be used in an automatic way to add meaning to code.

use Doctrine\ORM\Mapping as ORM;
/**
 * @ORM\Entity
 * @ORM\Table(name="blog")
 */
class Person {}

In this example a comment is added in front of a class to tell doctrine what this class is. This is a poor mans implementation of Annotations in Java.

But then Hack introduced attributes

In the Hack language attributes are introduced that replaces this somewhat poor solution and introduces native attributes that can be added to a class or a function.

Class attributes

<<Entity, Table("blog")>>
class Person {
}

With reflection these attributes can be retrieved at runtime.

$rc = new \ReflectionClass(Person::class);
var_dump($rc->getAttributes());

Function attributes

Attributes can be placed above a method/function. It can be used for a MVC framework to determine the entrypoint and routing. Something that is used a lot in Java EE. Together with a typed return value HACK is almost looking like Java.

class IndexController {
  <<GET,POST,Path("persons/list")>>
  public function list(int $start) : JsonResponse {}
}

Argument attributes

Also attributes in the arguments of a function are supported. With this some extra information can be added to an argument. Something that is not possible at all with the PHP style annotations.

function baz(<> int $id) {}

$rf = new \ReflectionFunction('baz');
$attrs = $rf->getParameters();
var_dump($attrs[0]->getAttributes());

The getAttributes seems to be missing from the current HACK manual but for what I can tell it works. It outputs the following array

array(1) {
  ["param"]=>
  array(0) {
  }
}

Special attributes

One particular interesting attribute that can be used for functions is __Memoize. This implements a caching mechanism called memoization. This can be used when you know a function always returns the same result for the same arguments. (When writing pure functions this is the case).

When running the following example the string “called function with argument $a\n” is outputted twice. The second call for test(5) is cached and the result is returned immediately without executing the function again.

<<__Memoize>> 
function test(int $a) {
  $i = 5;
  echo "called function with argument $a\n";
  return $i+$a;
}
test(5);
test(1);
test(5);

As the hack manuals warns you should not overdo caching because the result of every call to a function will be stored into memory. But it is a nice and elegant way of turning on caching for a function than (re)implementing the same caching mechanism over and over again.

Nice improvement

The biggest improvement of using attributes instead of Document annotations is the clear seperation of comments and actual machine readable/meaningful description. In the following snippet all comments can be removed without affecting the actual meaning of the code. The entity attribute will be still available after removing the comment but all “extra” information for the developer or other tools are not as they don’t play any role at runtime.

namespace My\ObjectModel;
/**
 * Class that describes a person
 * @author Leon
 * @copyright GPL
 * @enz..
*/
<<entity>>
class Person {
} 

I think attributes in Hack are a nice improvement to Hack to replace the PHP style document annotations. Annotations/attributes should be part of the language instead of some temporary solution. Hack has some more nice improvements like Collections, Async, Enums, Generics, Lambdas, etc..