Specifically, why does the following code output nil instead of 1?
class Foo
class << self
@bar = 1
def bar
@bar
end
end
end
p Foo.bar
In the << self block, self is an instance of #<Class:Foo>.
class Foo
puts "self in Foo declaration is: #{self} #{self.class} #{self.object_id}"
class << self
@bar = 1
puts "self in Foo.self declaration is: #{self} #{self.class} #{self.object_id}"
def bar
puts "self in class method is #{self} #{self.class} #{self.object_id}"
@bar
end
end
end
p Foo.bar
This code outputs:
self in Foo declaration is: Foo Class 69910818825400
self in Foo.self declaration is: #<Class:Foo> Class 69910818825380
self in class method is Foo Class 69910818825400
So a slight modification to your code, that works as expected, is:
class Foo
@bar = 1
class << self
def bar
@bar
end
end
end
p Foo.bar
This is in no way different from:
class Foo
@bar = 1
def bar; @bar end
end
Instance variables belong to objects and are always looked up on self. bar is an instance method, so the @bar inside bar belongs to some instance of Foo (self is the receiver of bar at that point). The @bar at the beginning belongs to the class itself (self is Foo at that point).
Those are simply two completely different objects. The two ´@bar`s are completely unrelated.
In your example: the first @bar belongs to the singleton class of Foo, the second @bar belongs to the instance of the singleton class of Foo (i.e. Foo).
Here's how you could make it work:
class Foo
@bar = 1
def self.bar; @bar end
end
nilseems fairly intuitive to me, considering you do not create an instance of Foo. Using class variables (i.e.,@@bar) it works fine. Well, never mind. In a normal class the instance variable can indeed be set like you more or less try in the Eigenclass:class A;@a=1;def self.a;@a;end;end;p A.aThis would print 1 just fine, without creating an instance of A.