Special cased?

This confused me a bit

class A
@a = 2
@@a = 3
def self.a
puts [@a, @@a]
end
end

class B < A; end

A.a # [2, 3]
B.a # [nil, 3]

shouldn’t @a just lookup @@a in the parent? Different treatment for
different types of variables?

-r

El Sábado, 19 de Diciembre de 2009, Roger P. escribió:

class B < A; end

A.a # [2, 3]
B.a # [nil, 3]

shouldn’t @a just lookup @@a in the parent? Different treatment for
different types of variables?

When you write:

class A
@a = 2

take into account that @a=2 is just parsed when loading class A for
first
time.
When you later do “class B < A; end”, the Ruby interpreter doesn’t read
the
line “@a = 2” again as it already parsed class A and just stored in
memory the
methods of class A.

El Sábado, 19 de Diciembre de 2009, Iñaki Baz C. escribió:

class A
@a = 2

take into account that @a=2 is just parsed when loading class A for first
time.
When you later do “class B < A; end”, the Ruby interpreter doesn’t read the
line “@a = 2” again as it already parsed class A and just stored in memory
the methods of class A.

Take a look to this example which shows the same concept:

irb> class A
puts “I’m A”
end
I’m A
nil

irb> class B < A; end
nil

Hi –

On Sat, 19 Dec 2009, Iñaki Baz C. wrote:

class A
@a = 2

take into account that @a=2 is just parsed when loading class A for first
time.
When you later do “class B < A; end”, the Ruby interpreter doesn’t read the
line “@a = 2” again as it already parsed class A and just stored in memory the
methods of class A.

Also, instance variables are always pegged to “self”.

class A
puts self # A
@x = 1
end

class B < A
puts self # B
puts @x # nil
end

Every object, including every Class object, has its own supply of
instance variable “slots”, and the meaning of @var is always
self.instance_variable_get("@var").

David

Hi –

On Sat, 19 Dec 2009, Roger P. wrote:

class B < A; end

A.a # [2, 3]
B.a # [nil, 3]

shouldn’t @a just lookup @@a in the parent? Different treatment for
different types of variables?

I think you mean shouldn’t it just look up @a (not @@a) in the parent
– and the answer is no :slight_smile: A and B are different objects, and
therefore do not share instance variables.

David

Roger P. wrote:

shouldn’t @a just lookup @@a in the parent?

Nope - class variables (@@) have nothing to do with instance variables
(@). @a in this case is just an instance variable of the class object,
so @a in class B is different to @a in class A

Class variables are a very strange beast with bizarre semantics. I would
avoid them if I were you.

El Sábado, 19 de Diciembre de 2009, David A. Black
escribió:> I think you mean shouldn’t it just look up @a (not @@a) in the parent

– and the answer is no :slight_smile: A and B are different objects, and
therefore do not share instance variables.

class A
@a = “hello”

def self.say
  puts defined?(@a).inspect
end

end

A.say
=> “instance-variable”
nil

class B < A ; end

B.say
nil
nil

But as I already explained, the line ‘@a = “hello”’ is just parsed by
Ruby
interpreter when loading class A.

When creating class B (which inherits from A) the Ruby parser doesn’t
read the
whole class A definition again. Instead it already has in memory all the
class/instance methods defined for class A so it wouldn’t read ‘@a =
“hello”’
anymore.

And because of it, B class object doesn’t know @a as its instance
variable, it
knows nothing about @a.

Hi –

On Sun, 20 Dec 2009, Iñaki Baz C. wrote:

end
nil
Exactly :slight_smile:

But as I already explained, the line ‘@a = “hello”’ is just parsed by Ruby
interpreter when loading class A.

When creating class B (which inherits from A) the Ruby parser doesn’t read the
whole class A definition again. Instead it already has in memory all the
class/instance methods defined for class A so it wouldn’t read ‘@a = “hello”’
anymore.

And because of it, B class object doesn’t know @a as its instance variable, it
knows nothing about @a.

The general rule about instance variables (that they are strictly
per-object) is still in effect, though, even if you do it some other
way:

class A
end

class B < A
end

A.instance_variable_set("@a", “hello”)
p B.instance_variable_get("@a") # nil

David

Class variables are a very strange beast with bizarre semantics. I would
avoid them if I were you.

Yeah they must be special cased so that beginning users can use them
with abandon and it will “just work.”

Interesting.

in
class A
@@a = 3
end

class B < A
def go
@@a
end
end

in B.new.go => 3…where is @@a stored?..it’s not in B…it’s not in
A’s nearest ancestor, which is “Object”…it’s special cased somehow?

Roughly paraphrasing a quote I heard once…
“after using ruby for 5 years, it is still surprising to me” (no offence
intended, of course :slight_smile:
Cheers.
-r

Roger P. wrote:

class A
@@a = 3
end

class B < A
def go
@@a
end
end

in B.new.go => 3…where is @@a stored?..it’s not in B…it’s not in
A’s nearest ancestor, which is “Object”…it’s special cased somehow?

I believe it’s picking up the value from class A, since that’s B’s
ancestor, and B doesn’t already have an @@a of its own.

It gets scarier though. Have a look at this:

class A
def a
@@a
end
def a=(v)
@@a = v
end
end
=> nil

class B < A
def a2
@@a
end
def a2=(v)
@@a = v
end
end
=> nil

ai = A.new
=> #<A:0x7f59fb532260>

bi = B.new
=> #<B:0x7f59fb52cbf8>

bi.a2 = 1
=> 1

ai.a
NameError: uninitialized class variable @@a in A
from (irb):3:in `a’
from (irb):23
from :0

bi.a
NameError: uninitialized class variable @@a in A
from (irb):3:in `a’
from (irb):24
from :0

bi.a2
=> 1

bi.a = 2
=> 2

ai.a
=> 2

bi.a
=> 2

bi.a2
=> 1

ai.a = 3
=> 3

ai.a
=> 3

bi.a
=> 3

bi.a2
=> 1

So which ‘version’ of the @@a class variable you see, depends on where
the method which reads it was defined… or something like that.

Hi –

On Sun, 20 Dec 2009, Roger P. wrote:

Class variables are a very strange beast with bizarre semantics. I would
avoid them if I were you.

Yeah they must be special cased so that beginning users can use them
with abandon and it will “just work.”

See this, from Matz:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/347355

especially:

(3) and lastly, and most importantly, do not use class variables,
unless you really really need them; they are fundamentally global
variables.

That’s the thing; they’re really hierarchy globals, but confusingly
similar to instance variables (of which they are essentially the
opposite) in appearance.

David