Sucht man nach einem Klassenvariablenkonzept für Ruby trifft man über kurz oder lang auf das @@-Konzept. Wer sich darauf einlässt kann schnell Probleme bekommen. Der Grund ist relativ einfach: @@-Variablen sind keine Klassenvariablen.
Einfache „Klassenvariablen“
class Cat @@size = :small def self.size @@size end def self.size= new_size @@size = new_size end def size @@size end end
expect(Cat.size).to be :small expect(Cat.new.size).to be :small Cat.size = :medium expect(Cat.size).to be :medium expect(Cat.new.size).to be :medium
Vererbung
class HouseCat < Cat end class Lion < Cat end
expect(Lion.size).to be :small Lion.size = :big expect(Lion.size).to be :big expect(HouseCat.size).to be :big
Hauskatze und Löwe teilen die selbe Variable, was zu erwarten war. Lässt sich das trennen?
@@-Variablen sind keine Klassenvariablen
class HouseCat < Cat end class Lion < Cat @@size = :big end
expect(Lion.size).to be :big expect(HouseCat.size).to be :big # !!!
Nein. Die gesetzte Variable gilt für die gesamte Klassenhierarchie aufwärts.
Superklassen haben übrigens keinen Zugriff:
class Cat def self.size @@size end end class Lion < Cat @@size = :big end
expect{ Lion.size }.to raise_error NameError
Richtige Klassenvariablen
Da in Ruby auch Klassen Objekte sind, sind Instanzvariablen dieser Objekte auch Klassenvariablen. Bemerkenswert ist hier die strenge Sichtbarkeitsbeschränkung: Selbst wenn @small
und self.size
in der selben Klassen definiert werden, kann self.size
nach der Vererbung in die HouseCat
nicht länger mit @small
auf die Klassenvariable von Cat
zurgreifen.
class Cat @size = :small def self.size @size end end class HouseCat < Cat end class Lion < Cat @size = :big end
expect(Lion.size).to be :big expect(Cat.size).to be :small expect(HouseCat.size).to be_nil
Aber hier können ja wieder Klassenhierarchievariablen helfen.