Rubyベストプラクティス 付録C Rubyワーストプラクティス その1

Ruby ベストプラクティスの最後を飾るのは 付録C Rubyワーストプラクティスです。やってしまいがちな失敗について述べたものです。「こうしたほうがいい」というのにくらべて「こうするとよくない、失敗しがち」という知見は実践的なものになりがちなのでとてもためになりますね。

  • 有害なクラス変数
    • クラス変数は継承先のクラスからも共有される。よりグローバルに近いスコープ
    • 用途によってはクラスのインスタンス変数を用いるほうが良い
      • 個人的には、サブクラスで先にクラス変数へ代入してから親クラスでクラス変数へ代入した時の挙動がかなりびっくりします
class A
end

class B < A
  @var = "var in B"
end

p B.class_variable_get(:@@var) # => "var in B"
begin
  p A.class_variable_get(:@@var)
rescue
 p $! # => #<NameError: uninitialized class variable @@var in A>
end

class A
  @var = "var in A"
end

p A.class_variable_get(:@@var) # => "var in A"
p B.class_variable_get(:@@var) # => "var in A" <- 親クラスの変更が伝播

まあこれはクラスツリーで共有されるというポリシーに則っているのでそうかなと思いますが、サブクラスが2つ以上あった場合がどうなるのかやや疑問だったのでやってみました。

class A
end

class B < A
  @@var = "var in B"
end

class C < A
  @@var = "var in C"
end

p B.class_variable_get(:@@var) # => "var in B"
p C.class_variable_get(:@@var) # => "var in C"

class A
  @@var = "var in A"
end

p A.class_variable_get(:@@var) # => "var in A"
p B.class_variable_get(:@@var) # => "var in A"
p C.class_variable_get(:@@var) # => "var in A"

class C
  @@var = "var in C, again"
end
p B.class_variable_get(:@@var) # => "var in C, again"

親クラス A でのクラス変数の代入はそれまで独立していた B と C のクラス変数を結び付けて、同じ変数にしてしまうようですね。ちょっと不思議です。

いきなり最初のトピックのクラス変数について脱線したので今日はここまで。
そういえば次の本には「プログラミングコンテストチャレンジブック」もいいかなと思いました。これも30分読書向けじゃないかもしれませんが。実際にサンプルコードを書きながらのほうが向いているかも。