Dartの型システムを飼い慣らせ:`Future` と `FutureOr` の深淵
DartのSound Null Safetyは、単なる「Nullポインタ例外を防ぐためのガード」ではない。コンパイラが型推論の段階で「実行時に値が存在するか否か」を静的に証明するための、強力な推論エンジンだ。
しかし、非同期処理において `Future
—
1. `Future` と `FutureOr` の決定的な境界線
多くの開発者がこの二つを混同しているが、設計意図は全く異なる。
`Future`:明示的な「値の不在」
これは「非同期処理の結果として、値が存在しない(null)可能性がある」ことを意味する。
- 用途: APIレスポンスが「データなし」を正常系として返す場合。
- 注意: 受取側は必ずNullチェック(または `if (res != null)`)を強制される。
`FutureOr`:同期と非同期の「ハイブリッド」
これは「処理の結果が即座に確定しているか(同期)、あるいはFutureとして返されるか(非同期)を型システムで抽象化する」ためのものだ。
- 用途: キャッシュ機構の実装。キャッシュヒットなら即座に `T` を返し、ミスなら `Future
` を返す。 - メリット: 無駄な `Future` インスタンスの生成を抑止し、VMのマイクロタスクキューを汚染しない。
—
2. 現場で「バグを埋め込まない」ための設計パターン
APIクライアントを例に、堅牢な設計を見てみよう。
import ‘dart:async’;
/// ユーザー情報を取得するリポジトリ
/// 戻り値に FutureOr を使うことで、パフォーマンスと型安全を両立する
abstract class UserRepository {
// キャッシュがあれば即座に返し、なければ非同期で取得する
FutureOr
}
class UserApiRepository implements UserRepository {
final Map
@override
FutureOr
// キャッシュヒット時は Future のオーバーヘッドを発生させない
if (_cache.containsKey(id)) {
return _cache[id];
}
// 非同期通信時は Future を返す
return _fetchFromNetwork(id);
}
Future
// ネットワーク処理…
return null; // 存在しない場合
}
}
// 利用側のコード
Future
// ここで FutureOr の真価が発揮される
// await を使うことで、同期/非同期を意識せず安全に型解決できる
final user = await repo.getUser(id);
// Null Safety により、userがnullである可能性を強制的に考慮させる
if (user == null) {
print(‘User not found.’);
return;
}
print(‘User: ${user.name}’);
}
なぜこれが美しいのか?
1. 不必要な非同期化の回避: キャッシュヒット時に `Future.value()` を生成すると、コンパイラはそれをイベントループのタスクとしてスケジュールする。`FutureOr` を使えば、同期的な戻り値は即座に評価され、VMのオーバーヘッドを最小化できる。
2. 型推論の完全性: `await` は `FutureOr
—
3. パフォーマンスの深層:コンパイラとVMの視点
DartのAOTコンパイラにとって、`Future
もし、あなたが `Future
- アンチパターン: `Future
- ?>` のような多重Null許容型。
- これが発生する場合、設計を見直すべきだ。空のリスト `[]` を返すのと、`null` を返すのでは、型安全性が天と地ほど違う。「データがない」という状態を `null` に押し付けない。「空」は「空」として型定義する。
—
4. チーフアーキテクトからの助言:Null安全を「守り」から「攻め」へ
実務において、Null安全を単なる「エラー回避ツール」として使っているうちは二流だ。「Nullを許容しない設計こそが、最もコストの低いドキュメントになる」ということを忘れてはならない。
1. APIの契約: `Future
2. 型変換のコスト: `FutureOr
結論
`Future
我々の仕事は、コンパイラが最も気持ちよく最適化できるよう、型という名の厳格なルールを書き記すことだ。コードレビューでは、妥協して `!` や `?` を付ける前に、「なぜこの型定義が最適なのか」を自問自答してほしい。
それが、伝説的なアーキテクトへの第一歩だ。