Kotlin の scope functions との上手な付き合い方

こんにちは、Native チームの @geckour です。
今回は、Kotlin の便利な関数である scope functions の概要と、そのうまい使い所の話をします。

Scope functions

Kotlin の scope functions として紹介されているものはいくつかのタイプに分類することができます。

関数名 拡張関数である コンテキストの参照方法 返却する値
let it スコープで最後に評価した値
run × - スコープで最後に評価した値
with ×: コンテキストを引数として指定する this スコープで最後に評価した値
apply this コンテキスト
also it コンテキスト
use it スコープで最後に評価した値

そんな中で、同じような働きをする let apply also の使い分けで悩んだことがある方も多いのではないでしょうか。
そこで、私達のチーム (僕) が辿った思考/志向の推移を紹介します。

パターン1: 返す値の特性で考える

少し話はそれますが、僕は .forEach {} で済むところにわざわざ .map {} を使うのは邪道である、という考えを持っています。
.map {} は拡張元のリストをスコープ内で加工した値のリストに変換して返却しますが、その返却された値を使わないのであれば .forEach {} を使えばいいし、不用意に .map {} を使うと「ああこの値は後で使うんだな」というミスリーティングを招いたり、他人がそのコードをいじる際にバグを生みやすくなると考えているからです。

その考え方をもとに、 let は加工した値を返すので、その値をスコープ外で必要としていない場合には使用を避けるべきでは?という考えに至りました。
つまり、基本的には apply / also を使って、加工した値が必要なときだけ let を使うという方針です。

よーし、これで心置きなく scope functions を使えるぞ、と思っていた矢先、公式ドキュメント に不穏な(?)記述を発見しました。

let can be used to invoke one or more functions on results of call chains.
let is often used for executing a code block only with non-null values. To perform actions on a non-null object, use the safe call operator ?. on it and call let with the actions in its lambda.
Another case for using let is introducing local variables with a limited scope for improving code readability.

つまり、「一時的なスコープ作るのに便利だよ」と言っているくらいなので、値を返すかどうかなどどうでも良さげなスタンスだったのです。

では apply の立場は…?と思い確認すると

Use apply for code blocks that don't return a value and mainly operate on the members of the receiver object. The common case for apply is the object configuration. Such calls can be read as “apply the following assignments to the object.”

とあり、つまりは「その名の通りオブジェクトをいじるときに使えるぜ」ということらしいのです。

パターン2: メソッド名に従う

はて…ならば全てメソッド名が示すとおりに使い分ければいいのでは?と思い、最近はこのパターンを採用しています。

  • Safe call operator (?.) を使うときは let
  • あるオブジェクトに対する処理をまとめたいときは apply
    • ネストが深くなって this が何なのかわかりづらくなるがスコープは作りたいときは let
  • あるオブジェクトを生成するついでに何かしたいときも apply

のような感じです。
おや、 also はどこに…?と気付いた方。ほぼ使わなくなりました。

終わりに

Kotlin は柔軟で自由である分、正攻法がわからず困ってしまう場面も多いと思います。
正解がわからずとも、これからもより良い方法を考えていく所存です。

皆さんのプラクティスもぜひ聞かせてください!

Quipper では一緒に働く仲間たちを募集しています。
是非お気軽にカジュアル面談にお越しください!