2017年9月なので少々前の話になるのですが、Rails のコミットログを見ていたらこんな変更を見つけました。
難しいことではなく、単に ||= を使っていたところを defined? でチェックし代入するように変更しています。
何が違うか
値が nil だった場合、変更前の書き方の場合は、「偽かチェックして、右辺を改めて算出する」のに対して、変更後はそれらが要りません。
「偽なら代入 ||= 」の場合
- 定義しているか -> ?
- 偽か -> チェックする
- 代入する値 -> 計算する
「defined? が偽なら代入」の場合
- 定義しているか -> チェックする
- 偽か -> なし
- 代入する値 -> なし
しかもこれが、このメソッドを通るたびに発生します。
自分は、真偽チェックと defined? と (Ruby の言語レベルの話として) どの程度コストが違うのか、というところまでは理解してないのですが、少なくとも defined? だけにすればやることが減るのは確かだと思います。
どんなケースに応用できるか
フレームワークレベルでこれを直せばなるほど意味があるように思いますが、それ以外でもどこかに役立てたいものです。
同様の修正が有効なのは、(追記しました)
- 右辺で複雑な計算をしている
- 結果として nil もしくは false が返って来うる
- 何度も実行されるが、右辺の返り値は変わらない
上記の場合でしょうか。
自分の書いているプログラムには思い当たらないです。残念。
追記: 特に早くしたい目的ではないのですが、代入するものの導出が複数行に渡り、 begin - end で書いているようなケースでは、見た目の複雑さが大きくは変わらないので積極的に使っていこうと思いました。
def client
@client ||= begin
# ... 何かすごい処理
Client.new
end
end
def client
unless defined?(@client)
# ... 何かすごい処理
@client = Client.new
end
@client
end