Dart/Flutterの非同期の仕組みについて思うところをつらつらと

2026/06/28 22:08公開
2026/06/28 23:24最終更新

Flutterって、フレームワーク自体の設計にけっこう粗が目立つ。

Dartのlintルールに「discarded_futures」「unawaited_futures」というものがある。これらは元々、Futureをawaitしなかったことによる意図しないバグを防ぐ目的のルールで、意図的に捨てていることをunawaited関数でラップして明示するか、大人しくawaitするかのどちらかに強制できる。

しかし、Flutter側の設計に目を向けると、大半のユースケースでFutureが捨てられることを想定した関数、つまり少数のユースケースのためにFutureを戻り値に設定している関数が大量に存在する。そのため、このルールに従おうと思うと、画面遷移のための大量の関数呼び出しをunawaitedでラップする必要がある。バグを防ぐためのlintが、大量のコードノイズを発生させるという状態である。2025年頃に「@awaitNotRequired」アノテーションがmetaパッケージに追加され、これがついている関数はFutureを捨てても怒られなくなった。現在のFlutterプロジェクトでは、急ピッチでNavigator.pushなどの関数にこのアノテーションを付ける作業が行われているが、苦肉の策感は否めない。

私が思うに、それぞれのユースケースで関数を分けるべきだったと思う。例えば、voidを返すNavigator.push、Futureを返すNavigator.pushReturningというように。そうすれば、静的解析に余計な負荷をかけずに済むし、awaitすべき関数とそうでない関数を簡単に区別できる。

ただこれは大規模API変更になるので、今更受け入れられるかは微妙なところ。シグネチャーも二重で定義が必要になり、ボイラープレートが増える。今までの慣習や記事が古くなる。結構影響はデカい。探してもメソッド分割に関する議論は全く見当たらなかったが、Issueを出すかはかなり悩むところ。すでに追加されてしまった@awaitNotRequiredとの兼ね合いも(分割の方針を取るとこのアノテーションの存在意義が行方不明に)。

ということを、私のプロジェクトにこの2つのlintルールを追加してみて思ったところ。lintの方向性は正しいのにその周辺がクソなので、このプロジェクトでは結局元に戻そうと思う。