Collections: Constructing

Using Hack collections is quite similar to using arrays. In fact, you can use Hack collections in regular <?php files given they are built directly into the HHVM runtime (the only caveat is that in <?php files, you have to prefix the collections with HH\).

Constructing a Hack collection can be done using new or what we call literal syntax. Both of these are essentially a hybrid of how you create arrays.

Literal Syntax

If you want to create a Hack collection and provide the collection explicit values (or key/value pairs), then you want to use literal syntax.

$collection = <CollectionType> { val1, val2, ... , valN };
$collection = <KeyedCollectionType> { key1 => val1, key2 => val2, ... , keyN => valN}
<?hh

namespace Hack\UserDocumentation\Collections\Constructing\Examples\Literal;

function run(): void {
  $vec = Vector {'A', 'B', 'C'};
  $ivec = ImmVector {'A', 'B', 'C'};
  $map = Map {'A' => 1, 'B' => 2, 'C' => 3};
  $set = Set {'A', 'B', 'C'};
  $pair = Pair {'A', 'B'};

  var_dump($vec);
  var_dump($ivec);
  var_dump($map);
  var_dump($set);
  var_dump($pair);
}

run();
Output
object(HH\Vector)#1 (3) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "C"
}
object(HH\ImmVector)#2 (3) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "C"
}
object(HH\Map)#3 (3) {
  ["A"]=>
  int(1)
  ["B"]=>
  int(2)
  ["C"]=>
  int(3)
}
object(HH\Set)#4 (3) {
  string(1) "A"
  string(1) "B"
  string(1) "C"
}
object(HH\Pair)#5 (2) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
}

You can use literal syntax anywhere array() can be used, including initializing expressions for object or class properties.

<?hh

namespace Hack\UserDocumentation\Collections\Constructing\Examples\ClassProp;

class A {
  public static Map<int, string> $users = Map {};
  public static array<int, string> $users_a = array();
  // Cannot do something like this because function calls
  // aren't allowed in static class property initializers
  //public static Map<int, string> $users_bad = Map {rand(0, 10) => 'a'};
}

function run(): void {
  A::$users[0] = "Joel";
  A::$users_a[0] = "Fred";
  var_dump(A::$users);
  var_dump(A::$users_a);
}

run();
Output
object(HH\Map)#1 (1) {
  [0]=>
  string(4) "Joel"
}
array(1) {
  [0]=>
  string(4) "Fred"
}

There are no type arguments for literal syntax (e.g., $v = Vector<int> {1}; is a syntax error). The typechecker will infer and keep track of the type internally.

Using new

You can also use new to create an instance of a Hack collection. However, you must either pass the constructor a Traversable (like an array) or null.

$collection = new <CollectionType> (?Traversable<Tv> $t);
$collection = new <KeyedCollectionType> (?KeyedTraversable<Tk, Tv> $t);
<?hh

namespace Hack\UserDocumentation\Collections\Constructing\Examples\UsingNew;

function convert(array<int> $arr): Vector<int> {
  var_dump($arr instanceof Traversable);
  return new Vector($arr);
}

function run(): void {
  $arr = array(1, 2, 3);
  var_dump(convert($arr));
}

run();
Output
bool(true)
object(HH\Vector)#1 (3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}