メタプログラミングRuby 付録A よく使うイディオム その2

その1 は第9章のラストと一緒になってしまいました。

  • A.2 nil ガード
    • a ||= val こういう書き方よくしますね
    • けど、ここの等価だと言ってるこのコードはちょっと間違ってますね。
a ||= []

if a != nil
  a = a
else
  a = []
end

と等しいと書いてありますが

  1. a が false の時も代入される
  2. そして a が真値の時は代入がされない

はずなので、こうだと思います。

if a
  a = []
end

代入文自体も値を持つことを考えるとより正確にはこうですね。

a || (a = [])

代入するかどうかはローカル変数だとどうでもよさそうですが、「ミミックメソッド」を使と差がわかります。

class A
  def x
    puts "@x : #{@x.inspect}"
    @x
  end
  def x=(val)
    puts "@x <- #{val.inspect}"
    @x = val
  end
end

a = A.new
puts "first"
a.x ||= []
puts "second"
a.x ||= []

実行結果

first
@x : nil
@x <- []
second
@x : []

これは、 and や or (&& や || も)が単に論理演算子であるだけでなくて制御構文としても働く("a and b" は a が偽値の時右辺を評価しない)ことと対応しているんじゃないかと思います。