Posted at

HHVM/Hack 型システム その1


型システムを制するものはHackを制す

Hack and HHVM Advent Calendar 2018も中盤になってきましたので、

Hackの型システムに慣れるために、色々みていきます

紹介するものは全てstrict前提です。


プリミティブ

公式ドキュメントにもありますが、まずは基本の型からです。

PHPとは微妙に異なります。


bool

boolは当然boolのみとなります。

<?hh // strict

namespace Acme\Hacklang;

class TypeSystem {

public function is(): bool {
return true;
}

public function is_is(bool $bool): bool {
return $bool;
}
}


int / float

intとfloatを混ぜて使うことはできません。

下記は共にTypeErrorです。

  public function is(): int {

return 1.0;
}

public function is_is(float $bool = 0.1): int {
return $bool;
}


string

文字列も当然それ以外は利用できません。


array

これまでも紹介してきた様にarrayはPHPと同様にarrayだけでは不十分となります。

文字列のarrayを宣言しておいてintとなるとErrorとなります。

下記のは全てTypeErrorです。

  public function failedStringVarray(): varray<string> {

return [1];
}

public function failedStringStringDarray(): darray<string, string> {
return ['hello' => 1];
}

public function failedStringArray(): array<string> {
return [1];
}

public function failedStringStringArray(): array<string, string> {
return ['hello' => 1];
}

public function failedNestedMixedArray(): array<mixed> {
return [
1,
'testing',
'hello' => 1234,
'nested' => [
1 => 2,
'testing',
'hello' => 1234,
]
];
}

public function failedMixedArray(): array<mixed, mixed> {
return [
1,
'testing',
'hello' => 1234,
'nested' => [
1 => 2,
'testing',
'hello' => 1234,
]
];
}


resource

PHPと同じです。

  public function is(): resource {

return \fopen("ftp://user:password@example.com/somefile.txt", "w");;
}


プリミティブ型以外で利用するものです。


void

戻りがないことの宣言です。

ユニットテストの場合は基本的にvoidになるので、記述しなければいけません。


混合系

普通のものから特殊なものまで様々です。


mixed

Hackで開発する上で一番厄介で、なるべく利用して欲しくないのがこのmixedです。

いろんな型に加え、nullとvoidが許容されます。

mixedが記述されると、様々な手法でTypecheckerに理解可能なコードに書き直す必要があります。

下記のコードを例にしましょう。

  public function mixedParameter(mixed $param): string {

return $param;
}

引数にmixedを使い、そのまま返却している例です。

これはこのままだとTypeErrorになるため処理が実行できません。

$paramが文字列かどうかを保証するコードに変更しなければいけません。

下記のコードは問題がないコードです。

  public function mixedParameter(mixed $param): string {

if($param is string) {
return $param;
}
return '';
}

invariantを利用することもできます。

mixedは使えば使うほど分岐処理などが増えていきますので、

注意が必要です。

  public function mixedParameter(mixed $param): string {

invariant($param is string, 'Type Error.');
return $param;
}


nonnull

nullではないことを表すものです。

?nonnullにすると、mixedと同じ意味になります

  public function nullableNonnull(): nonnull {

return 1234;
}


num

intとfloatが利用できる型です。

以下のは問題なく動作します。

  public function returnNum(): num {

if (true) {
return 1.0;
}
return 1234;
}


arraykey

intとstringが利用できる型です。

  public function returnKey(): arraykey {

if (true) {
return 'hello';
}
return 1234;
}


callable

PHPのものと意味は同じですが、記述方法が異なります。

HackではcallableだけではTypecheckerでOKになりません。

callableなものでも無名関数の引数・型、無名関数の戻りの宣言しなければなりません。

またPHPの場合は _invokeを実装したクラスも許容されていますが、

Hackの場合は _
invokeが実装されていてもcallableにはなりません。

  public function returnCallable(): (function(int): int) {

return function(int $int) {
return 1;
};
}


Tuple

多値をあらわすものです。

難しい型ではありません。

  public function returnTuple(): (int, string) {

return tuple(1, 'testing');
}


Classname

ライブラリ開発などで多用するであろう型です。

className::classを返却したり引数に利用できるところで利用できます。

下記のはものはstdClassの例です。

  public function returnClassname(): classname<\stdClass> {

return \stdClass::class;
}

Genericsを利用することで、様々なクラス名を扱うこともできます。

  public function returnGenericsClass<T as classname<T>>(T $name): T {

return $name;
}

今回は型の紹介のみでした。