Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Ruby: インスタンス変数初期化のメモ化`||=`はほとんどの場合不要

小ネタで恐縮です。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みたいなメソッドをこしらえたことならあります」

「ちなみに初期化ではないところのインスタンス変数で||=を使ったら、セッターっぽく見えたらしくて『これってセッターですか?』って聞かれたことあったんですけど『いえゲッターです』と返しました😆」

関連記事

Ruby: 私がメモ化を暗黙で使わない3つの理由(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。