Pages

Wednesday, March 26, 2014

Collection - Part- II




Examples 
Here are some more examples that showcase much of the functionality of the Hack collection interfaces and classes.
Collections are objects 
<?hh
 
function main() {
  // Collections are objects.
  $v Vector {123};
  echo is_array($v) ? '$v is an array' '$v is not an array';
  echo "\n";
  echo is_object($v) ? '$v is an object' '$v is not an object';
  echo "\n";
  var_dump($v);
}
 
main();
The above example will output:
$v is not an array
$v is an object
object(Vector)#1 (3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}
Reference-like Semantics 
<?hh
// Like all objects, collections has "reference-like"
// semantics for assignment, parameter passing, and
// foreach.
function foo($v) {
  $v[1] = 7;
}
 
function main() {
  $v1 Vector {123};
  $v2 $v1;
  foo($v2);
  var_dump($v1);
  echo "\n";
  foreach ($v1 as $key => $value) {
    echo $key " => " $value "\n";
    if ($key == 0) {
      $v1[2] = 9;
    }
  }
}
 
main();
The above example will output:
object(Vector)#1 (3) {
  [0]=>
  int(1)
  [1]=>
  int(7)
  [2]=>
  int(3)
}

0 => 1
1 => 7
2 => 9
Iterator Invalidation 
<?hh
// Certain kinds of modification, such as 
// removing an element, will cause iterators to 
// be invalidated (including foreach loops).
function main() {
  $m Map {'a' => 1'b' => 2'c' => 3'd' => 4};
  foreach ($m as $key => $value) { 
    echo $key " => " $value "\n";
    if ($key == 'a') {
      $m->remove('d');
    }
  }
}
 
main();
The above example will output:
a => 1
HipHop Fatal error: Uncaught exception 'InvalidOperationException' with message 'Collection was modified during iteration'
Key Not Present 
<?hh
// Using "$c[$k]" syntax or using the at() method
// will throw an exception if the specified key is 
// not present. Using the get() method will return 
// NULL if the specified key is not present.
function main() {
  $m Vector {};
  try {
    var_dump($m[0]);
  } catch (OutOfBoundsException $e) {
    echo "Caught exception 1\n";
  }
 
  try {
    var_dump($m->at(0));
  } catch (OutOfBoundsException $e) {
    echo "Caught exception 2\n";
  }
 
  try {
    var_dump($m->get(0));
  } catch (OutOfBoundsException $e) {
    echo "Caught exception 3\n";
  }
}
 
main();
The above example will output:
Caught exception 1
Caught exception 2
NULL
Const Interfaces 
<?hh
// The "read-only" style interfaces (such as ConstMap)
// can be used to indicate that a function will not 
// modify the collection.
function foo(ConstMap<string,int$mstring $k): int {
  echo $m[$k] . "\n";
}
 
function main() {
  $m Map {'a' => 1'b' => 2'c' => 3'd' => 4};
  foo($m'c');
}
The above example will output:
3
keys() method 
<?hh
// The keys() method can be used on Vector and Map
// to get a Vector of the keys.
function main() {
  $m Map {'a' => 1'b' => 2'c' => 3'd' => 4};
  $v $m->keys();
  var_dump($v);
}
 
main();
The above example will output:
object(Vector)#2 (4) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(1) "d"
}
map() method 
<?hh
// The map() method can be used on any collection to 
// get a concrete collection (usually the same type as
// the original) containing each value with some 
// operation applied.
function main() {
  $m Map {'a' => 1'b' => 2'c' => 3'd' => 4};
  $m2 $m->map(function(int $x):int { return $x 10; });
  var_dump($m2);
}
 
main();
The above example will output:
object(Map)#2 (4) {
  ["a"]=>
  int(11)
  ["b"]=>
  int(12)
  ["c"]=>
  int(13)
  ["d"]=>
  int(14)
}
filter() method 
// The filter() method can be used on any collection to 
// get a concrete collection (usually the same type as
// the original) containing the values that meet some
// condition.
function main() {
  $m = Map {'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4};
  $m2 = $m->filter(function(int $x):bool { return $x % 2 == 0; });
  var_dump($m2);
}
 
main();
The above example will output:
object(Map)#2 (2) {
  ["b"]=>
  int(2)
  ["d"]=>
  int(4)
}
Iterables 
<?hh
// All Iterables support map() and filter() to support 
// chaining.
 
function main() {
  $m Map {'a' => 1'b' => 2'c' => 3'd' => 4};
  $result $m->filter(function(int $x):bool { return $x == 0; })
              ->map(function(int $x):int { return $x 1; });
  foreach ($result as $key => $value) {
    echo $key " => " $value "\n";
  }
}
 
main();
The above example will output:
b => 3
d => 5
Lazy Views 
<?hh
// The Iterable objects returned by view() and
// items() are 'lazy' views of the original 
// collection; this means that if a value in the 
// underlying collection is changed, the lazy view
// will reflect this change. Also, certain kinds 
// of modifications that invalidate iterators 
// (such as removing an element) will also
// invalidate lazy views.
function main() {
  $m Map {'a' => 1'b' => 2'c' => 3'd' => 4};
  $iterable $m->items();
  $m['a'] = 100;
  $i 0;
  foreach ($iterable as $t) {
    echo $t[0] . " => " $t[1] . "\n";
    if ($i == 2) {
      echo "Removing key 'a'\n";
      $m->remove('a');
    }
    ++$i;
  }
}
main();
The above example will output:
a => 100
b => 2
c => 3
Removing key 'a'
HipHop Fatal error: Uncaught exception 'InvalidOperationException' with message 'Collection was modified during iteration'
Vector 
<?hh
function main() {
  $vec Vector {11};
  $vec->addAll(Vector {223344});
  var_dump($vec);
}
 
main();
The above example will output:
object(Vector)#1 (4) {
  [0]=>
  int(11)
  [1]=>
  int(22)
  [2]=>
  int(33)
  [3]=>
  int(44)
}
Map 
function main() {
  $map = Map {'a' => 11};
  $map->setAll(Map {'b' => 22, 'c' => 33});
  var_dump($map);
}
 
main();
The above example will output:
object(Map)#1 (3) {
  ["a"]=>
  int(11)
  ["b"]=>
  int(22)
  ["c"]=>
  int(33)
}
Building a Concrete Collection 
<?hh
// A concrete collection can be built from an 
// Iterable or KeyedIterable by passing it to a 
// collection constructor.
function main() {
  $m Map {'a' => 11'b' => 22'c' => 33};
  $v = new Vector($m);
  var_dump($v);
}
 
main();
The above example will output:
object(Vector)#1 (3) {
  [0]=>
  int(11)
  [1]=>
  int(22)
  [2]=>
  int(33)
}
General Collection Interfaces 
<?hh
// Example showing add(), items(), and the general collection interfaces
function process_elements<T>(ConstCollection<T$in): OutputCollection<T> {
  $out Vector {};
  if (!($in instanceof ConstVector)) {
   return null;
  }
  foreach ($in->items() as $elm) {
    if ($elm 1) {
      $out->add($elm);
    }
  }
  return $out;
}

function main(): void {
  $x Vector {123};
  var_dump(process_elements($x));
}

main();
The above example will output:
object(HH\Vector)#2 (2) {
  [0]=>
  int(2)
  [1]=>
  int(3)
}
Generators 
<?hh
// Generators implement the Iterator interface; 
// a generator can be passed anywhere where an
// Iterator is expected.
function foo(Iterator<int$it) { .. }
function g() { yield 1; yield 2; }
 
function main() {
  $gen g();
  foo($gen);
}
 
main();
Converting to Indexish 
Real-world, existing code
<?hh
// This function does a relational join on two mappish style arrays into one
// mappish style array
function array_compose($f$g): array {
  $ret = array();
  foreach ($f as $x => $y) {
    if (array_key_exists($y$g)) {
      $ret[$x] = $g[$y];
    }
  }
  return $ret;
}
Possible Indexish modification #1
<?hh
// Use Indexish to be able to pass Map or Vector, in addition
// to arrays, to this function and return an array like before. Notice how
// foreach and bracket syntax is being used.
function array_compose<T1T2T3>(
  Indexish<T1T2$f,
  Indexish<T2T3$g
): array<T1T3> {
  $ret = array();
  foreach ($f as $x => $y) {
    if (array_key_exists($y$g)) {
      $ret[$x] = $g[$y];
    }
  }
  return $ret;
}
Possible Indexish modification #2
<?hh
// Use Indexish to be able to pass Map or Vector in addition
// to arrays, to this function and return a Map, which is what this
// function is actually returning in practice. Notice how
// foreach and bracket syntax is being used.
function map_compose<T1T2T3>(
  Indexish<T1T2$f,
  Indexish<T2T3$g
): Map<T1T3> {
  $ret Map {};
  foreach ($f as $x => $y) {
    if (array_key_exists($y$g)) {
      $ret[$x] = $g[$y];
    }
  }
  return $ret;
}
Test Code
<?hh
// Copyright 2004-present Facebook. All Rights Reserved.
 
function main_indexish(): void {
  $arr1 = array(12345);
  $arr2 = array(678910);
  var_dump(array_compose($arr1$arr2)); // original
  var_dump(array_compose($arr1$arr2)); // modified
  var_dump(map_compose($arr1$arr2));
 
  $map1 Map {=> 1=> 2=> 3=> 4=> 5};
  $map2 Map {=> 6=> 7=> 8=> 9=> 10};
  var_dump(array_compose($map1$map2)); // original
  var_dump(array_compose($map1$map2)); // modified
  var_dump(map_compose($map1$map2));
}
 
main_indexish()
The above example will output:
array(4) {
  [0]=>
  int(7)
  [1]=>
  int(8)
  [2]=>
  int(9)
  [3]=>
  int(10)
}
array(4) {
  [0]=>
  int(7)
  [1]=>
  int(8)
  [2]=>
  int(9)
  [3]=>
  int(10)
}
object(Map)#1 (4) {
  [0]=>
  int(7)
  [1]=>
  int(8)
  [2]=>
  int(9)
  [3]=>
  int(10)
}
array(4) {
  [0]=>
  int(7)
  [1]=>
  int(8)
  [2]=>
  int(9)
  [3]=>
  int(10)
}
array(4) {
  [0]=>
  int(7)
  [1]=>
  int(8)
  [2]=>
  int(9)
  [3]=>
  int(10)
}
object(Map)#3 (4) {
  [0]=>
  int(7)
  [1]=>
  int(8)
  [2]=>
  int(9)
  [3]=>
  int(10)
}

Limitations 
1.    Collections do not support taking elements by reference for performance and type safety reasons.
2.    Collections do not support dynamic properties.
3.    <, <=, >, and >= are not currently supported for collections (these will raise an error at runtime), though these will likely be supported in the future.

Future work on collections 
For this first version of Hack collections, there are features that did not make the cut. 
1.    Better support for iterators:
o    Bidirectional iterators (ability to move both forward and backward)
o    Ability to quickly get an iterator pointing to the last element
o    find() method for quickly getting an iterator for a given key (Map) or for a given value (Set)
o    findKey() method for quickly getting an iterator for a given index (Vector)
o    Swapping items via iterators
o    Comparing two iterators for equality (i.e., check if they point to the same element in the same collection)
2.    Supporting object keys for Map, and supporting object values for Set.
3.    Methods for finding or removing elements by value in O(n) time.
4.    Generic support for erasing multiple items cleanly and efficiently (ex. an idiom for erasing elements during iteration)
5.    Other possible data structure types such as LinkedList, SortedMap, MultiSet, MultiMap, etc..
6.    insert() method for quickly inserting an element at an arbitrary position in an order-preserving collection (this would be useful if we later support LinkedList).

No comments:

Post a Comment