Hack言語の「Shapes」と「名前付き型」:設計の迷いを断ち切る境界線
こんにちは。Hack言語の世界へようこそ。
HHVMの深淵を覗き込み、型チェッカーと毎日対話していると、多くの開発者が「このデータ構造、`shape`で定義すべきか、それとも`class`(名前付き型)にするべきか?」という迷宮に足を踏み入れていることに気づきます。
Hackの`shape`は構造的部分型(Structural Subtyping)の恩恵を最大限に引き出せる強力な武器ですが、闇雲に使うとドメインモデルが崩壊します。今日は、この境界線をどう引くべきか、現場の視点から紐解いていきましょう。
—
1. そもそも「Shapes」とは何者か?
`shape`は、一言で言えば「キーと値の型が固定された、軽量な連想配列」です。
type UserProfile = shape(
‘id’ => int,
‘username’ => string,
‘is_verified’ => bool,
);
この定義により、`$user[‘id’]` は常に `int` であることが保証されます。クラスを定義するほどではないが、ただの `dict
—
2. 構造的部分型 vs 名前付き型:境界線はここだ
では、なぜ迷うのでしょうか?それは、`shape`が「構造」だけで型を判断するからです。
構造的部分型(Shape)の強み:柔軟性
`shape`は「同じ形をしていれば、それは同じ型」とみなされます。APIのレスポンスや、一時的なデータ加工には最適です。
名前付き型(Class)の強み:ドメインの固定
`class`は「同じ形をしていても、別物」として扱われます。そこにメソッド(振る舞い)を付与し、状態の整合性をカプセル化できるのはクラスだけです。
使い分けの黄金ルール
- Shape: 「ただのデータ」を運ぶとき。外部との境界(JSONデコード、設定値など)。
- Class: 「振る舞い」を伴うとき。ビジネスロジックの中心、状態変化が伴うオブジェクト。
—
3. 実践:設計の現場で見極める
例えば、「ユーザーの住所情報」を扱うケースを考えてみましょう。
Shapeで書くべきケース(情報の受け渡し)
APIから受け取ったJSONをバリデーションするような場所では、`shape`が最適です。
// 外部からのデータ構造を定義
type Address = shape(
‘city’ => string,
‘zip’ => string,
);
function processAddress(Address $addr): void {
// 構造さえ合っていればOK。軽量で高速。
echo “City: ” . $addr[‘city’];
}
Classで書くべきケース(ロジックの付与)
もし住所に「配送可能エリアかどうかを判定する」というビジネスルールが含まれるなら、`class`に昇格させるべきです。
class Address {
public function __construct(
private string $city,
private string $zip,
) {}
// ここにビジネスロジックを持たせる
public function isDeliverable(): bool {
return $this->city === ‘Tokyo’;
}
}
—
4. 陥りやすい罠:エラーを読み解く
初学者がよく直面するのが「形は同じなのに型エラーになる」という現象です。
type A = shape(‘id’ => int);
type B = shape(‘id’ => int);
function test(A $a): void { / … / }
$b = shape(‘id’ => 1);
test($b); // これ、実は通ります!
Hackの`shape`は構造が一致していれば代入可能ですが、「名前付きのエイリアス」を定義した瞬間、意図が明確になります。
陥りやすいミス:
`shape`に新しいフィールドを追加した際、古い関数が「未定義のキーへのアクセス」でエラーを吐くのは、実は型チェッカーがあなたを守っている証拠です。これを避けるために、`optional`なフィールド(`?`を付ける)を適切に使い分けましょう。
type OptionalShape = shape(
‘id’ => int,
‘email’ => ?string, // emailはあってもなくても良い
);
—
最後に:型と友だちになるために
Hackの型システムは、あなたの「意図」をコンパイラに伝えるための言語です。
- 「ただのデータ」なら`shape`で軽快に。
- 「システムの状態」なら`class`で堅牢に。
この使い分けができるようになれば、あなたのコードは格段に読みやすく、そして壊れにくくなります。「型エラー」は敵ではありません。あなたの設計の甘さを指摘してくれる、最も有能なレビュアーだと思ってください。
ここをクリアすれば、Hackの基本はバッチリマスターできたも同然です。さあ、次はどんな複雑なドメインに挑んでみますか?またいつでも相談してくださいね。