28. 型エラーの検出
◦ 関数の戻り値の型は int でなければいけない
◦ ところが、引数の $b が float なので $c は int + float = float である
◦ というわけで、戻り値の型が正しくないと文句を言っている
2014/05/02 社内勉強会資料 28
$ vi test.hh
<?hh
function add_error(int $a, float $b): int {
$c = $a + $b;
return $c;
}
$ hh_client check
/.../test.hh:4:10,11: Invalid return type
/.../test.hh:2:39,41: This is an int
/.../test.hh:2:28,32: It is incompatible with a float
29. 型エラーの修正
◦ intval 関数を入れることで $c の型が int になった
◦ 単に int にキャストする方法でも同じ
2014/05/02 社内勉強会資料 29
$ vi test.hh
<?hh
function add_error_fixed(int $a, float $b): int {
$c = intval($a + $b);
return $c;
}
$ hh_client check
No errors!
30. Nullable
◦ 型の先頭に ? を書くと null 許容型になる
このプログラムには型エラーがあります (次のスライドで説明)
2014/05/02 社内勉強会資料 30
$ vi test.hh
<?hh
function add_null(?int $a, int $b): int {
$c = $a + $b;
return $c;
}
31. Nullable (型エラーの検出)
◦ $a は算術演算子 “+” で使われるので int か float でなければいけない
◦ ところが $a は null 許容型である
◦ というわけで、型のエラーだと文句を言っている
2014/05/02 社内勉強会資料 31
<?hh
function add_null(?int $a, int $b): int {
$c = $a + $b;
return $c;
}
$ hh_client check
/.../test.hh:3:8,9: Typing error
/.../test.hh:3:8,9: This is a num (int/float) because
this is used in an arithmetic operation
/.../test.hh:2:19,22: It is incompatible with a nullable
type
32. Nullable (型エラーの修正)
◦ null のときは 0 を代入することで、演算の箇所での $a は int になった
◦ 三項演算子を使って書いても同じ
2014/05/02 社内勉強会資料 32
$ vi test.hh
<?hh
function add_null(?int $a, int $b): int {
if ($a == null) {
$a = 0;
}
$c = $a + $b;
return $c;
}
$ hh_client check
No errors!
33. Shape
2014/05/02 社内勉強会資料 33
$ vi test.hh
<?hh
type person = shape('name' => string, 'age' => int);
function is_adult(person $p) : bool {
return $p['age'] >= 20;
}
function test() {
$taro = shape('name' => 'Taro', 'age' => 25);
echo is_adult($taro) . "¥n";
}
◦ Key の値が固定された配列
◦ 右辺の型に person という名前を付けている (type aliasing; 後述)
34. Shape (型エラーの検出)
◦ $no_name には “name” フィールドが無い
◦ is_adult 関数の引数 $p は person 型で “name” フィールドが定義済み
◦ というわけで、引数の型が正しくないと文句を言っている
2014/05/02 社内勉強会資料 34
function is_adult(person $p) : bool { ... }
function test() {
$no_name = shape('age' => 25); // name が無い
echo is_adult($no_name) . "¥n";
}
$ hh_client check
/.../test.hh:10:17,24: Invalid argument
/.../test.hh:9:14,18: The field 'name' is missing
/.../test.hh:4:19,24: The field 'name' is defined
36. Type Aliasing
◦ 右辺のデータ型に左辺の別名を付ける
◦ プログラムが分かりやすくなる
2014/05/02 社内勉強会資料 36
$ vi test.hh
<?hh
type point = shape('x' => int, 'y' => int);
function new_point(int $x, int $y) : point {
return shape('x' => $x, 'y' => $y);
}
function get_x(point $p) : int { return $p['x']; }
function get_y(point $p) : int { return $p['y']; }
37. Type Aliasing (newtype)
◦ newtype を使うと、ファイルの外側からは右辺が見えなくなる
◦ プログラムのモジュール化に役立つ
2014/05/02 社内勉強会資料 37
$ vi test.hh
<?hh
newtype point = shape('x' => int, 'y' => int);
function new_point(int $x, int $y) : point {
return shape('x' => $x, 'y' => $y);
}
function get_x(point $p) : int { return $p['x']; }
function get_y(point $p) : int { return $p['y']; }
38. Type Aliasing (型エラーの検出)
◦ point の実体が shape(‘x’ => int, …) だということは隠されている
◦ というわけで、$p はコンテナではなく point だと文句を言っている
2014/05/02 社内勉強会資料 38
<?hh
require 'test.hh';
function main() : void {
$p = new_point(1, 2);
$p['x'] = 3;
}
$ hh_client check
/.../main.hh:6:3,9: This is not a container, this is an
object of type point
/.../main.hh:5:38,42: You might want to check this out
40. hh_client と HHVM
HHVM では実行開始時に型検査するわけではない
◦ 関数の先頭で仮引数と実引数の型が合致しているか検査
◦ 関数を抜けるときに戻り値の型が合致しているか検査
hh_client がエラーにするコードも HHVM では実行できる
2014/05/02 社内勉強会資料 40
$ cat type_error.hh
<?hh
function test($cond): int { return $cond ? 1 : 'foo'; }
print test($argv[1]) . "¥n";
$ hhvm type_error.hh 1
1
$ hhvm type_error.hh 0
Fatal error: Value returned from test() must be of type
int, string given in /.../type_error.hh on line 3