Class instance variables, class variables and constants

Hello,

Thanks to the code in attach, I've figured out what is now completely obvious to me:

CLASS VARIABLE (@@something)
- Inherited by subclasses
- SAME ALLOCATION: If it's changed in Child, then it will change in Parent

CONSTANTS (Something)
- Inherited by subclasses
- PRIVATE ALLOCATION: If it's changed in Child, it will NOT change in parent

CLASS INSTANCE VARIABLES (@something)
- NOT Inherited by subclasses. They will simply be nil. Scope = Class
- DIFFERENT ALLOCATION: If it's changed in Child, it will NOT change in parent

I am sending this email to the mailing list so that if some Ruby newbie has the same problem with variable scope, they might find this email (and find it useful).

David A. Black wrote:

"I think Matz is planning to change class variables in 2.0 so that they
are class/module scoped rather than hierarchy scoped."

But wouldn't it make class variables (@@something) the same as class instance variables (@something)?

Here's the code I used to figure things out:

···

-----------------------------------------------------

#!/usr/local/bin/ruby -w

class Outer
         @@class_var=10
         GlobalVar=100
         @civ=1000

         class Second < Outer

                 @@class_var=11
                 GlobalVar=101
                 @civ=1001

                 def Second::class_var
                         @@class_var
                 end

                 def Second::class_var=(what)
                         @@class_var=what
                 end

                 def Second::civ
                         @civ
                 end

                 def Second::civ=(what)
                         @civ=what
                 end

         end

         def Outer::class_var
                 return @@class_var
         end

         def Outer::class_var=(what)
                 @@class_var=what
         end

         def Outer::civ
                 @civ
         end

         def Outer::civ=(what)
                 @civ=what
         end

end

class Third < Outer

         def self::class_var
                 return @@class_var
         end

         def Third::class_var=(what)
                 @@class_var=what
         end

         def Third::class_var
                 @@class_var
         end

         def Third::class_var=(what)
                 @@class_var=what
         end

         def Third::civ
                 @civ
         end

         def Third::civ=(what)
                 @civ=what
         end
end

puts "Outer"
p Outer::class_var
p Outer::GlobalVar
p Outer::civ
puts "Outer::Second"
p Outer::Second::class_var
p Outer::Second::GlobalVar
p Outer::Second::civ
puts "Third"
p Third::class_var
p Third::GlobalVar
p Third::civ
puts

Outer::Second::class_var=13
Outer::Second::GlobalVar=103
Outer::Second::civ=1003

puts "Outer"
p Outer::class_var
p Outer::GlobalVar
p Outer::civ
puts "Outer::Second"
p Outer::Second::class_var
p Outer::Second::GlobalVar
p Outer::Second::civ
puts "Third"
p Third::class_var
p Third::GlobalVar
p Third::civ
puts

Third::class_var=14
Third::GlobalVar=104
Third::civ=1004

puts "Outer"
p Outer::class_var
p Outer::GlobalVar
p Outer::civ
puts "Outer::Second"
p Outer::Second::class_var
p Outer::Second::GlobalVar
p Outer::Second::civ
puts "Third"
p Third::class_var
p Third::GlobalVar
p Third::civ
puts

# Just checking...
p Third::Second::class_var
p Third::Second::GlobalVar
p Third::Second::civ

But there is more fun when singleton classes get involved:

class A
   @@var = :A
   C = :CA
end

class B
   @@var = :B
   C = :CB

   a = A.new
   class ::A
     p [@@var, C] # => [:A, :CA]
     def foo
       [@@var, C]
     end
   end
   def a.bar
     [@@var, C]
   end
   class << a
     p [@@var, C] # => [:B, :CB]
     def baz
       [@@var, C]
     end
   end
   p a.foo # => [:A, :CA]
   p a.bar # => [:B, :CB]
   p a.baz # => [:B, :CB]
   p [@@var, ::a::C, C, class << a;C;end] # => [:B, :CA, :CB, :CB]
   class << a
     @@var = :ASing # this changes B's @@var [*]
     C = :CASing # this creates a new C for a's sing. class
   end
   p [@@var, ::a::C, C, class << a;C;end] # => [:ASing, :CA, :CB, :CASing]
   p a.foo # => [:A, :CA]
   p a.bar # => [:ASing, :CB]
   p a.baz # => [:ASing, :CASing]
end

Some points:
- singleton classes don't have their own class variables, but they can have their own constants
- constant and class var lookup use the lexical scope, so it depends "where" you do something (that's why bar's C and baz's C are different)
- (lexical) singleton-class-scopes are skipped when accessing class vars (that's why [*] changes B's @@var and not A's @@var)

I hope that helps and doesn't totally confuse you :wink:

Dominik

···

On Mon, 20 Feb 2006 15:22:04 +0100, Tony Mobily <merc@mobily.com> wrote:

Hello,

Thanks to the code in attach, I've figured out what is now completely obvious to me:

CLASS VARIABLE (@@something)
- Inherited by subclasses
- SAME ALLOCATION: If it's changed in Child, then it will change in Parent

CONSTANTS (Something)
- Inherited by subclasses
- PRIVATE ALLOCATION: If it's changed in Child, it will NOT change in parent

CLASS INSTANCE VARIABLES (@something)
- NOT Inherited by subclasses. They will simply be nil. Scope = Class
- DIFFERENT ALLOCATION: If it's changed in Child, it will NOT change in parent

Dňa Pondelok 20 Február 2006 15:22 Tony Mobily napísal:

"I think Matz is planning to change class variables in 2.0 so that they
are class/module scoped rather than hierarchy scoped."

But wouldn't it make class variables (@@something) the same as class
instance variables (@something)?

Nope. Class variables could still be "inherited", but they wouldn't clobber
stuff up the hierarchy if modified.

David Vallner

Hi,

Some points:
- singleton classes don't have their own class variables, but they can have their own constants
- constant and class var lookup use the lexical scope, so it depends "where" you do something (that's why bar's C and baz's C are different)
- (lexical) singleton-class-scopes are skipped when accessing class vars (that's why [*] changes B's @@var and not A's @@var)

I hope that helps and doesn't totally confuse you :wink:

OK. One hour later, this is became clear...
I'd write the points above in a different order:

- singleton classes can have their own constants

- singleton classes don't have their own class variables. (Lexical) singleton-class-scopes are skipped when accessing class vars

- constant and class variable lookup use the lexical scope, so it depends "where" you do something

Now... I do have a question. On one hand, I really, really want to know all these fine details. That's just my nature.
However, in this case, I must ask: is this going to be *useful* at any point in time?
When would you want to set a constant for a singleton class?

The rest makes perfect sense to me: a singleton class could realistically need access a class variable. And I realise that I need to know that constant and class variable lookup use the lexical scope. But... singleton constants...?

Just curious!

Merc.

Hi --

···

On Tue, 21 Feb 2006, Dominik Bathon wrote:

Some points:
- singleton classes don't have their own class variables, but they can have their own constants

There's an interesting discussion of this in an earlier thread; see
especially:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/65527

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

Dňa Pondelok 20 Február 2006 23:35 Tony Mobily napísal:

When would you want to set a constant for a singleton class?

Hardly ever? It's not like you need more instances to always get the same
value.

David Vallner