小ネタで恐縮です。RuboCopスタイルガイドからRubyのメモ化||=
に関する部分を抜粋します。
⚓コンストラクタでは不要な||=
を避け、単なる代入にするのが望ましい
「Rubyのインスタンス変数(@
で始まる変数)は代入されるまではnil
なので、||=
はほとんどの場合不要」という理由です。
原文のdisjunctiveは論理学の用語で、ORの堅苦しい表現です。
# bad
def initialize
@x ||= 1
end
# good
def initialize
@x = 1
end
⚓条件変数初期化のショートハンド
こちらはインスタンス変数ではない条件変数に対する||=
で、メモ化が望ましいとされていますが、次の警告があります。
# bad
name = name ? name : 'Bozhidar'
# bad
name = 'Bozhidar' unless name
# good - nameがnilかfalseの場合にのみ'Bozhidar'を設定
name ||= 'Bozhidar'
警告: ブーリアン変数の初期化には||=
を使わないこと
現在の値がnil
ではなく、たまたまfalse
だった場合を考えればわかりますね。
# bad - enabledがfalseだった場合にもtrueに設定されてしまう
enabled ||= true
# good
enabled = true if enabled.nil?
はみ出しつっつき
いつもお世話になっているBPS Webチームのkazzさんとこの話をしました。
「うん、初期化のインスタンス変数に||=
は確かに不要、コピペで持ってきたコードにありがちです」
「自分はメモ化割と好きなので||=
をよく使ってたこともあるんですが、メモ化は基本的に最適化なので最初からやらなくてもいいものだし、メモ化があちこちに散らばるとわかりにくくなることもあるんですよ」「メモ化は高速化が必要になってから検討する方がいいんですね」「find
メソッドなんかはActiveRecordの側で既にキャッシュされるから、それをさらにメモ化する意味はありませんし」「@kamipoさんが最近のRails最適化でメモ化をやってたりしますけど、そのぐらいに考える方がメモ化をやりすぎずに済みそうですね」
「あと気をつけないといけないのは、nil
が入ってくる可能性のあるオブジェクトには||=
のメモ化が効かないということ: nil
が入っていると結局毎回読み込みが実行されちゃうので最適化されない」「あ〜そうか!」「以前それを回避するためにmemoize
みたいなメソッドをこしらえたことならあります」
「ちなみに初期化ではないところのインスタンス変数で||=
を使ったら、セッターっぽく見えたらしくて『これってセッターですか?』って聞かれたことあったんですけど『いえゲッターです』と返しました😆」