an elephant of a different colour: hack
DESCRIPTION
Slides from my GTA-PHP Meetup talk about Hack which is the Facebook version of the PHP programming language which runs under their HHVM runtime environment for PHP. The focus of my talk was the language improvements that the Facebook team has added to PHP. There's a lot of information in the presenter's notes, so if you're interested in Hack scroll down to see the extras.TRANSCRIPT
An Elephant of a Different Colour: Hack
Reduce your Server Load, Reuse your Code and Recycle your PHP Skills with HHVM & Hack
Image Copyright Keith Evans. This work is licensed under the Creative Commons Attribution-Share Alike 2.0 Generic Licence. To view a copy of this licence, visit http://creativecommons.org/licenses/by-sa/2.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San
Francisco, California, 94105, USA.
Just in case you’re not up to speed on this HHVM
stuff…
© Some rights reserved by Dave Hamster
© Some rights reserved by Andy Barnes
© Some rights reserved by Casey Fleser
HackXHP
Async
Collections
Lambda
Types
XHP<?hhrequire_once('lib/init.php');$class = "greeting";$subject = "Toronto & area";$body = <p class={$class}>$hello {ucwords($subject)}</p>;echo <x:doctype> <html> <head><title>Hello XHP</title></head> <body>{$body}</body> </html></x:doctype>;
<!DOCTYPE html><html><head><title>Hello XHP</title></head><body> <p class="greeting">$hello Toronto & Area</p></body></html>
XHP
XHP emits HTML without
the whitespace andformatting. I’ve added
itfor readability.
<?hhrequire_once('lib/init.php');$list = <ul />;for ($i = 0; $i < 7; $i += 1) { $list->appendChild(<li>{date('l', time() + $i * 86400)}</li>);}echo $list;
<ul> <li>Monday</li> <li>Tuesday</li> <li>Wednesday</li> <li>Thursday</li> <li>Friday</li> <li>Saturday</li> <li>Sunday</li></ul>
XHP
• Available for Zend PHP too!
• See https://github.com/facebook/xhp
• Can use HTML() to emit unescaped HTML but don’t.
CollectionsVector
Map
Set
Pair
0 => ‘Apples’,1 => ‘Bananas’,2 => ‘Oranges’
[Red] => ‘Apples’,[Yellow] => ‘Bananas’,[Orange] => ‘Oranges’
0 => ‘Apples’,1 => ‘Bananas’
‘Apples’,‘Bananas’‘Oranges’
Vectors[0] => "zero"[1] => "one"[2] => 2
<?hh$v = Vector { "zero", "one" };
$v[] = 2;
$v->add($v->count());
$v->removeKey(0);
print_r($v);
[0] => “one"[1] => 2[2] => 3
[0] => "zero"[1] => "one"[2] => 2[3] => 3
[0] => "zero"[1] => “one”
Old School Arrays
Can you spot the difference between
the Hack and PHP results?
<?php$v = array("zero", “one”);
$v[] = 2;
array_push($v, count($v));
unset($v[0]);
print_r($v); [1] => "one"[2] => 2[3] => 3
[0] => “zero"[1] => “one"[0] => "zero"[1] => "one"[2] => 2[0] => "zero"[1] => "one"[2] => 2[3] => 3
Vectors
• Always 0 .. (count -1)
• Values are not hashed / indexed
• Use Sets for this
• Can use [] to append, but not unset() to remove
PairPair Object( [0] => Pair Object ( [0] => Batman [1] => Robin ) [1] => xhp_p Object ( [tagName:protected] => p [attributes:xhp_x__composable_element:private] => Array () [children:xhp_x__composable_element:private] => Array ( [0] => The dynamic Duo ) [source] => /home/vic/prog/presentation/collections/pair.php:4 ))
<?hhrequire_once('../lib/init.php');$dynamicDuo = Pair {'Batman', 'Robin'};$p = Pair {$dynamicDuo, <p>The dynamic Duo</p>};print_r($p);
Pair
• Pairs must contain two items of any type
• Pairs are always immutable
• Items are accessed with [0] and [1]
Map
Map Object( [CA] => Canada [US] => United States [MX] => Mexico [NI] => Nicaragua)
<?hh$map = Map { 'CA' => 'Canada', 'US' => 'United States'};$map->add(Pair {'MX', 'Mexico'});$map['NI'] = 'Nicaragua';print_r($map);
Map
• Maps contain key / value Pairs
• Keys can only be integers or strings
• Values can be of any type
• Order is preserved
Set
HH\Set Object( US CA MX NI Has Canada)
• Can only contain integers orstrings
• Unordered
<?hh$s = Set {'US', 'CA'};$s->add('MX');$s[] = 'NI';$s[] = ($s->contains('CA') ? 'Has' : 'Lacks') . ' Canada';print_r($s);
Types<?hhfunction add(int $a, int $b): int {
return $a + $b;}var_dump(add(1, 2));var_dump(add(1.5, 2));
int(3)HipHop Fatal error: Argument 1 passed to add() must be an instance of int, double given in /home/vic/prog/presentation/type.php on line 4
Types<?hhfunction add(
shape('x' => int, 'y' => int) $p1,shape('x' => int, 'y' => int) $p2
): shape('x' => int, 'y' => int) {return shape(‘x' => $p1['x'] + $p2['x'], 'y' => $p1['y'] +
$p2[‘y']);}var_dump(add(['x' => 3, 'y' => 4], ['x' => 5, 'y' => 25]));
array(2) { ["x"]=>int(8) ["y"]=>int(29)}
Types<?hhtype Coord = shape('x' => int, 'y' => int);function add(Coord $p1, Coord $p2): Coord {
return ['x' => $p1['x'] + $p2['x'], 'y' => $p1['y'] + $p2['y']];}var_dump(add(['x' => 3, 'y' => 4, 'z' => 1], ['x' => 5, 'y' => 25]));var_dump(add(['x' => 3, 'z' => 4], ['x' => 5, 'y' => 25]));array(2) {[“x”]=>int(8), [“y"]=>int(29)}
HipHop Notice: Undefined index: y in /home/vic/prog/presentation/typedef.php on line 4
array(2) {[“x”]=>int(8), ["y"]=>int(25)}
Generics<?hhclass Accumulator<T> {
function __construct(private T $value) {}function add(T $value) { $this->value +=
$value; }function get():T { return $this->value; }
}$accumulateInts = new Accumulator<int>(5);$accumulateInts->add(4);var_dump($accumulateInts->get());
$accumulateFloats = new Accumulator<float>(0.7);$accumulateFloats->add(1.6);var_dump($accumulateFloats->get());
$accumulate = new Accumulator([5]);$accumulate->add([4,9]);var_dump($accumulate->get());
int(9)
float(2.3)array(2) {
[0]=>int(5) [1]=>int(9)}
Generics<?hhclass Accumulator<T> {
function __construct(private T $value) {}function add(T $value) { $this->value +=
$value; }function get():T { return $this->value; }
}$accumulateInts = new Accumulator<int>(5);$accumulateInts->add(4);$accumulateInts->add(4.4);var_dump($accumulateInts->get());
float(13.4) !
Nullable Types<?hhfunction printNum(?int $num) {
echo "num is ";echo is_null($num) ? "null" :
$num;echo "\n";
}printNum(1);printNum(null);printNum("Five");
num is 1num is nullHipHop Warning: Argument 1 to printNum() must be of type ?int, string given in /home/vic/prog/presentation/nullable.php on line 6num is Five
Types<?hhclass MyClass<T as SomeInterface> {
function __construct(private T $v) {}}
newtype Secret as BaseClass = MyClass;
Lambda<?php$countries = [
'US' => 'United States','CA' => 'Canada','MX' => 'Mexico',
];uasort($countries, function ($a, $b) {
return $a > $b;});var_dump($countries);
array(3) { ["CA"]=> string(6) "Canada" ["MX"]=> string(6) "Mexico" ["US"]=> string(13) "United States"}
Lambda
array(3) { ["CA"]=> string(6) "Canada" ["MX"]=> string(6) "Mexico" ["US"]=> string(13) "United States"}
<?hh$countries = [
'US' => 'United States','CA' => 'Canada','MX' => 'Mexico',
];uasort($countries, ($a, $b) ==> $a > $b);var_dump($countries);
Lambda
<?hh$add = ($a, $b) ==> $a + $b;
function curry($callable, $value) {return $v ==>
$callable($value, $v);}
$addFour = curry($add, 4);var_dump($addFour(5));
int(9)
User Attributes<?hh<< MyAnnotation('Unicorn', 42) >>function bar() {}
$rc = new ReflectionFunction('bar');print_r($rc->getAttributes());
Array( [MyAnnotation] => Array ( [0] => Unicorn [1] => 42 )
)
User Attributes
• You can add attributes / annotations to classes, methods, functions and arguments.
• You can specify more than one set of user attributes:<< Foo(1), Bar(2) >>
• You can’t use constants or variables in attributes
Async
• I lied; hhvm’s async is more c# than node.
• Library functions like evhttp_async_get() don’t return Awaitable’s
• So they don’t seem to play well together
• PocketRent/beatbox uses async, but I don’t grock it
class Foo{}
class Bar { public function getFoo(): Foo { return new Foo(); }}
async function gen_foo(int $a): Awaitable<?Foo> { if ($a === 0) { return null; }
$bar = await gen_bar($a); if ($bar !== null) { return $bar->getFoo(); }
return null;}
Async
async function gen_bar(int $a): Awaitable<?Bar> { if ($a === 0) { return null; }
return new Bar();}
gen_foo(4);
This is the exampleFacebook provided on GitHub for async.
More• See hhvm.com
• The debugger is command line, and very good: hhvm -m debug
• Sara Golemon is giving a talk tomorrow night about HHVM and hack, and it will be live streamed:http://www.meetup.com/sf-php/events/159404382/
• Framework for Hack:https://wiki.pocketrent.com/beatbox/start
• I promise to blog about Hack at http://blog.vicmetcalfe.com/