【入門編】【中級者向け】`Tuple`型による複数戻り値の分解:配列ベースの戻り値からの脱却と型安全な分解 – Hack言語 コア・静的型システムとHHVMのアーキテクチャ解析バイブル

こんにちは!Hackの静的型システムとHHVMの裏側の世界へようこそ。チーフアーキテクトの私です。

他のプログラミング言語からHackの世界に飛び込んできた開発者の多くが、最初に「おや?」とつまずくポイント、そして同時にHackの美しさに魅了される瞬間があります。それが「データの複数戻り値の扱い方」です。

今回は、配列(Array)のインデックスアクセスという泥臭い世界から脱却し、Hackの強力な `Tuple`(タプル)型と直感的な分解構文を使って、型安全で美しいコードを書く極意を一緒にマスターしていきましょう。ここをクリアすれば、Hackの型システムの恩恵を肌で感じられるようになりますよ!

—

1. なぜ「配列ベースの複数戻り値」は危険なのか?

PHPや、動的型付けの香りを残したコードを書いていると、関数から複数の値を返したいときに、つい次のような配列(Array)を使ってしまいがちですよね。

<<__Strict>>
namespace HackMasterclass;

// ユーザー情報をデータベースから取得して、[名前, メール, 年齢] の配列を返す関数(アンチパターン)
function fetch_user_legacy(int $id): array {
// 実際にはDBから取得する処理
return [“Alice”, “alice@example.com”, 30];
}

このコード、一見すると問題なさそうに見えますが、呼び出し側で大変なことになります。

<<__Strict>>
// 呼び出し側
<<__EntryPoint>>
function main_legacy(): void {
$data = fetch_user_legacy(1);

// インデックス「1」が何を表しているか、記憶に頼るしかない…!
// もしインデックスの順番が変わったら? 型は `mixed` なのでコンパイラは何も守ってくれません。
echo “名前: ” . $data[0] . “\n”;
echo “メール: ” . $data[1] . “\n”;
}

🧠 アーキテクトからの警鐘:

`array` や要素数の決まっていない配列で複数戻り値を扱うのは、型チェッカーの目を欺くようなものです。`$data[1]` がメールアドレスなのか年齢なのか、コードを書いた本人ですら3ヶ月後には忘れてしまいます。何より、型が `mixed` に落ちるため、Hackの厳格な静的型付け(Strict Mode)のメリットが完全にスポイルされてしまいます。

—

2. 救世主:`Tuple` 型による型安全な複数戻り値

そこで登場するのが `Tuple`(タプル)型 です。
タプルとは、「固定長かつ、各要素の型が厳密に決まっている直積型」のことです。Hackでは、括弧 `(T1, T2, …)` を使って表現します。

先ほどのユーザー取得関数を、Tuple型を使って書き直してみましょう。

<<__Strict>>
namespace HackMasterclass;

// [名前(string), メール(string), 年齢(int)] を確実に返す
function fetch_user(int $id): (string, string, int) {
// 各要素の型がシグネチャと完全一致している必要がある
returntuple(“Alice”, “alice@example.com”, 30);
}

> 💡 ワンポイントメモ:
> Hackではタプルの構築に `tuple(“a”, “b”, 1)` もしくは単に `(“a”, “b”, 1)` のリテラル構文が使えます。型定義側は必ず `(string, string, int)` のように括弧で囲みます。

これで、関数が「何を・どの順序で返すか」が型レベルで完全に担保されました。

—

3. リスト代入(Destructuring)による優雅な分解

型が安全になっただけでなく、Hackにはタプルの値を一瞬で変数にバラす(分解する)ための非常にスマートな構文が用意されています。それがリスト代入(Destructuring)です。

実際のコードで見てみましょう。

<<__Strict>>
namespace HackMasterclass;

<<__EntryPoint>>
function main(): void {
$userId = 1;

// タプルをそのまま個別の変数に美しく分解!
list($name, $email, $age) = fetch_user($userId);

// IDEの補完も、型チェッカーの解析も完璧に効く
echo “名前: {$name} (年齢: {$age}歳)\n”;
echo “連絡先: {$email}\n”;
}

この分解構文の素晴らしいところは、左辺の変数 `$name`, `$email`, `$age` の型が、右辺のタプルの型定義(`string, string, int`)から自動的に推論される点です。手動で型を書く必要すらありません。

—

4. 陥りやすい文法エラーと型チェッカーの挙動

ここで、Hackの厳格な型チェッカー(hhvm)がどのようにあなたを守ってくれるか、いくつかの「やりがちなミス」を見ておきましょう。

エラーケース 1: 要素数のミスマッチ

// 戻り値は3つの要素を持つタプルなのに…
list($name, $email) = fetch_user(1);
// ❌ コンパイルエラー!
// タプルの要素数(3つ)と代入先(2つ)が一致しません。

配列であれば実行時まで気づかないバグが、Hackならビルド(型チェック)の瞬間に検知されます。

エラーケース 2: 型の不一致による代入

// $age は int のはずなのに、stringを受け取ろうとしたら?
list($name, $email, $age) = fetch_user(1);
// もし関数側で $age の位置に文字列を返していたら、
// $age を数値として扱おうとした瞬間に型チェッカーが怒ってくれます。

—

5. まとめ:配列脳からTuple脳へ切り替えよう

今回は、配列ベースの曖昧な戻り値から脱却し、`Tuple` 型とリスト代入を使って型安全なコードを書く手法を解説しました。

  • 配列のインデックスアクセスは、型が失われ(`mixed`になり)、バグの温床になります。
  • `Tuple` 型 `(T1, T2, …)` を使えば、固定長の複数戻り値を明確に型定義できます。
  • `list(…)` 構文 を使えば、可読性を落とさずにエレガントに変数を分解できます。

「複数の値を返したいときは、まずTupleが使えないかを考える」。
この習慣を身につけるだけで、あなたの書くHackコードの堅牢性は劇的に跳ね上がります。

ここをクリアしたあなたなら、もうHackの静型システムの心地よさを十分に実感できているはずです。
さあ、次のコードブロックへ進みましょう。あなたのハッキングを応援しています!

タイトルとURLをコピーしました