ZEND -> HHVM
かつて、栄華を極めたVRMMORPG【ZEND ONLINE】。
しかし、MMORPG以外の娯楽の普及によってその人気も徐々に下火となっていった。当ゲームも、衰退の波に抗うことができずに本日をもってサービスが終了することが決定した。長らくゲームを続けていたヘビープレイヤーであったザンプは、最後だからとサービス終了まで今まで利用してこなかったチートツールを使ってゲームを楽しんでいた。運営側も最後だからということで、そういった不正には寛容だった。
そして、終了時刻を迎えたときに強制ログアウトされるものだと思っていたのだがどうも様子がおかしい。今まで遊んでいたゲームのキャラクターが意思をもち会話をしだしたのだ。
――「ようこそHHVMのセカイへ」
冒頭に謎小説を差し込めるのはブログの特権。どうも僕です。というわけで、Hack言語についてちょっといじってみたので記事を書いてみました。
Hackは、Facebookにより開発されたプログラミング言語である。オープンソースとして公開されており、同社が開発したPHP実行環境のHipHop仮想マシン (HHVM) で動作する。
HackはHHVM環境で動作するPHPの新しいバージョンと見なすこともできるが、PHPとは異なり動的/静的双方の型システムが使用可能となっている。FacebookではHackを「漸進的型付き言語」であるとしており、これがHackの強みとされている。
ちなみに件のやつはコレのことです。Facebookの開発した言語です。僕の中ではほぼAltPHPって認識です(トランスパイルとかないけど、PHPコードはほぼ流用できるのでそういう認識です。)。
公式
Hack · Programming Productivity Without Breaking Things
チュートリアルさわってみた。
これただの読み物だと思ってたんですけど、書いて覚える形式になってたんですね。なので、これについてのなんかアレコレ書くことにしたのでした。
チュートリアル
Hack · Programming Productivity Without Breaking Things


ということでやってみた。ぶっちゃけただの翻訳記事……。
前半戦
Ex.1
チュートリアル開始的なことが書いてます。
Ex.2
Hackのおまじないについて。PHPなら&let?phpで開始だけどHackの場合は……。
<?hh // Hackは常に<?hhで開始します
Ex.3
Hackの関数には型がある。
<?hh function my_negation(bool $x): bool { return !$x; } function add_one(int $x): int { return $x+1; }
Ex.4
Hackのエラーは下線部に複数表示されます。
Ex.5
型の前に "?" をつけるとnullが許容されます。
<?hh function f(?int $x): void { var_dump($x); } function test(): void { f(123); f(null); }
Ex6.
User型の判定。先ほどのnullの話に通ずるものがある……。
<?hh interface User { public function getName(): string; } function get_user_name(?User $user): string { if($user !== null) { return $user->getName(); } return '<invalid name>'; } function test(User $user) { $name1 = get_user_name($user); $name2 = get_user_name(null); }
Ex7.
nullの処理。例外処理編
<?hh interface User { public function getName(): string; } function get_user_name(?User $user): string { if($user === null) { throw new RuntimeException('Invalid user name'); } return $user->getName(); } function test(User $user) { $name1 = get_user_name($user); $name2 = get_user_name(null); }
Ex8.
Hackはコレクション型にVector、Set、Mapがあります。
Ex9.
これらのコレクション型はジェネリックである
<?hh function test(): Vector<int> { $vector = Vector {1, 2, 3}; return $vector; }
Ex10.
ラムダ。
<?hh function vector_add1(Vector<int> $v): Vector<int> { return $v->map($x ==> $x + 1); } function vector_mult2(Vector<int> $v): Vector<int> { return $v->map($x ==> $x * 2); }
Ex.11
前半戦終了!後半戦はエキスパートモードらしいですよ。
後半戦
Ex12.
クラスのメンバの初期化は必須
<?hh class Point { private float $x; private float $y; public function __construct(float $x, float $y) { $this->x = $x; $this->y = $y; } }
Ex13.
先ほどのやつはこれでもいける。
<?hh class Point { public function __construct( private float $x, private float $y ) {} }
Ex14.
独自のジェネリックもつくれる。
<?hh class Store<T> { public function __construct(private T $data) {} public function get(): T { return $this->data; } public function set(T $x): void { $this->data = $x; } } function test(): Store<string> { $data = 'Hello world!'; $x = new Store($data); return $x; }
Ex15.
ジェネリックの制約も…
<?hh interface MyInterface { public function foo(): void; } function call_foo<T as MyInterface >(T $x): T { $x->foo(); return $x; }
Ex16.
'this' で派生型を指します
<?hh class MyBaseClass { protected int $count = 0; public function add1(): this { $this->count += 1; return $this; } } class MyDerivedClass extends MyBaseClass { public function print_count(): void { echo $this->count; } } function test(): void { $x = new MyDerivedClass(); $x->add1()->print_count(); }
Ex17.
型が長すぎる場合、エイリアスが使用できる
<?hh type Matrix<T> = Vector<Vector<T>>; function first_row<T>(Matrix<T> $matrix): Vector<T> { return $matrix[0]; }
Ex18.
固定長の配列:タプル
<?hh function my_first_pair((int, bool) $pair): bool { list($_, $result) = $pair; return $result; }
Ex19.
Key値固定の配列:シェイプ
<?hh type my_shape = shape( 'field1' => int, 'field2' => bool, ); function first_shape(): my_shape { $result = shape('field1' => 1, 'field2' => true); return $result; }
Ex20.
関数の型にも指定
<?hh function apply_int<T>((function(int): T) $callback, int $value): T { return $callback($value); }
Ex21.
XHPでの書き方。
<?hh function build_paragraph(string $text, string $style): :div { return <div style={$style}> <p>{$text}</p> </div>; }
Ex22.
Opaque型で型の隠ぺいできる。
<?hh newtype user_id = int; function make_user_id(int $x): user_id { return $x; } function user_id_to_int(user_id $x): int { return $x; }
Ex23.
継承は<< Override >>。
<?hh class MyBaseClass { public function get_user(): MyUser { return new MyUser(); } } class MyDerivedClass extends MyBaseClass { <<Override>> public function get_user(): MyUser { return new MyUser(); } }
Ex24.
'require' について
<?hh class C { protected function bar(): void {} } interface I { public function foo(): void; } trait T { require extends C; require implements I; public function do_stuff(): void { $this->bar(); // We can access bar because we used "require extends" $this->foo(); } }
Ex25.
完
といった感じでした。後半は集中力切れていつものように雑にまとめてしまいましたが、こいつはそんな感じの言語です。HHVM環境でしか動作しないところが今のとこネックな気がするけど、第二のPHPとして使うのはありっぽい気がします。