Class variables - a surprising result

class Sup
@@x = "A"
def test
print @@x
end
end

class Sub1 < Sup
 @@x = "B"
end

class Sub2 < Sup
 @@x = "C"
end

Sup.new.test
Sub1.new.test
Sub2.new.test

I expect this to print “ABC”, and yet it prints “CCC”. Why is this?

Class variable allocation is per class scope, not per subclass scope.
Sub1, Sub2 and Sup really do share their class variables. Now don’t
ask me for the “why exactly”…

-Martin

···

On Thu, Aug 21, 2003 at 06:33:09PM +0900, Jason Williams wrote:

class Sup
 @@x = "A"
 def test 
  print @@x 
 end
end

class Sub1 < Sup
 @@x = "B"
end

class Sub2 < Sup
 @@x = "C"
end

Sup.new.test
Sub1.new.test
Sub2.new.test

I expect this to print “ABC”, and yet it prints “CCC”. Why is this?

class Sup
 @@x = "A"
 def test
  print @@x
 end
end

class Sub1 < Sup
 @@x = "B"
end

class Sub2 < Sup
 @@x = "C"
end

Sup.new.test
Sub1.new.test
Sub2.new.test

I expect this to print “ABC”, and yet it prints “CCC”. Why is this?

hwow - for the stupid (me):
@@x seems to be the same thing for the whole inheritance-hierarchy (or
whatever this thing is called)… but i thought every class has it’s very
own class-vars…
i mean… what’s the purpose of that? hmmm. i did never notice this. i guess
it just seems so strange due to me not being familiar with it this way…
and - am i right? - in java it would say ABC, wouldn’t it?
strange…

patrick

That’s what I would expect to happen, although I am not sure
I could give a good explanation as to why it is “obvious”
that it should work that way.

As to what exactly is happening, the assignments to @@x are
not inside any method. The assignments are processed as they
are read in, not in the order that ‘.new’ (or any other method)
is called on any of the classes. Perhaps the following will
give you a better idea of why you ended up with ‘CCC’:

- - - - start

class Sup
@@x = “A”
@@line = 0
def Sup.Ctest
@@line += 1
@@x += @@x[0,1]
print @@line, “-”, @@x, “\n”
end
end

Sup.Ctest # first test
Sup.Ctest # second test

class Sub1 < Sup # define subclass
@@x = “B”
end

Sub1.Ctest # third test
Sup.Ctest # fourth test

- - - - end

This produces:
1-AA
2-AAA
3-BB
4-BBB

I am not sure if that really helps you with the question
you’re asking, though. Note that since you are only using
class variables for this example, we can simply use a class
method. There is no need for creating any instances of
either of these classes, as far as the class variables are
concerned.

To get back to why there would be only one @@x for a class
and all it’s subclasses, let me refer to a line from the
“Programming Ruby” (pickaxe) book: “A class variable is
shared among all objects of a class, and is also accessible
to the class methods…”.

Any object which is an instance of ‘Sub1’ is also, by
definition, an instance of ‘Sup’. If a class variable is
shared among all objects of class ‘Sup’, then the exact
same variable must also be shared with the objects which
happen to be from class ‘Sub1’.

···

At 6:33 PM +0900 8/21/03, Jason Williams wrote:

class Sup
 @@x = "A"
 def test
  print @@x
 end
end

class Sub1 < Sup
 @@x = "B"
end

class Sub2 < Sup
 @@x = "C"
end

Sup.new.test
Sub1.new.test
Sub2.new.test

I expect this to print “ABC”, and yet it prints “CCC”.
Why is this?


Garance Alistair Drosehn = gad@gilead.netel.rpi.edu
Senior Systems Programmer or gad@freebsd.org
Rensselaer Polytechnic Institute or drosih@rpi.edu

Class variable allocation is per class scope, not per subclass scope.
Sub1, Sub2 and Sup really do share their class variables. Now don’t
ask me for the “why exactly”…

I was fooled by this as well. I don’t know why I intuitively would
think that a subclass would get its own scope, but I did. Having your
own scope as a subclass would be a really neat addition, though. But
perhaps a reason from Matz would shed light?

/ David

Patrick Zesar wrote:

class Sup
 @@x = "A"
 def test
  print @@x
 end
end

class Sub1 < Sup
 @@x = "B"
end

class Sub2 < Sup
 @@x = "C"
end

Sup.new.test
Sub1.new.test
Sub2.new.test

I expect this to print “ABC”, and yet it prints “CCC”. Why is this?

[…]
and - am i right? - in java it would say ABC, wouldn’t it?

No, in Java this kind of source couldn’t be implemented.
In Java you can’t define a class variable which was already
defined by the super class (same with instance variables,
of course).

However, you can reassign them. But even this can’t be done
that way, i.e. in the class definition. The “.Main(args)”
may be a place to do that. There are also some ugly hacks
possible to execute some code when the class is loaded, …

but nevertheless, you can’t redefine a class variable
in Java. You can just reassign them. And that’s exactly
what Ruby did, too. :slight_smile:

···


Volker Grabsch
—<<(())>>—
\frac{\left|\vartheta_0\times{\ell,\kappa\in\Re}\right|}{\sqrt
[G]{-\Gamma(\alpha)\cdot\mathcal{B}^{\left[\oint!c_\hbar\right]}}}

On Thu, 21 Aug 2003 19:02:43 +0900, David Heinemeier Hansson
david@loudthinking.com wrote (more or less):

Class variable allocation is per class scope, not per subclass scope.
Sub1, Sub2 and Sup really do share their class variables. Now don’t
ask me for the “why exactly”…

I was fooled by this as well. I don’t know why I intuitively would
think that a subclass would get its own scope, but I did. Having your
own scope as a subclass would be a really neat addition, though. But
perhaps a reason from Matz would shed light?

A class-instance variable is one in which the scope is specific to a
given (sub)class.

Am I correct in dimly recalling that Ruby has support for
class-instance variables?

Cheers,
Euan
Gawnsoft: http://www.gawnsoft.co.sr
Symbian/Epoc wiki: http://html.dnsalias.net:1122
Smalltalk links (harvested from comp.lang.smalltalk) http://html.dnsalias.net/gawnsoft/smalltalk

Hi,

Class variable allocation is per class scope, not per subclass scope.
Sub1, Sub2 and Sup really do share their class variables. Now don’t
ask me for the “why exactly”…

I was fooled by this as well. I don’t know why I intuitively would
think that a subclass would get its own scope, but I did. Having your
own scope as a subclass would be a really neat addition, though. But
perhaps a reason from Matz would shed light?

They are variables. If you can’t update values, how they can be
variables.

class Sup
 @@x = "A"          # declare @@x, set @@x as "A"
 def test 
  print @@x 
 end
end

class Sub1 < Sup
 @@x = "B"          # set @@x as "B"
end

class Sub2 < Sup
 @@x = "C"          # set @@x as "C"
end

Sup.new.test        # print the value of @@x ("C")
Sub1.new.test       # ditto.
Sub2.new.test       # ditto.

Class variables are like global variables whose scope is limited to
the inheritance tree.

						matz.
···

In message “Re: Class variables - a surprising result” on 03/08/21, David Heinemeier Hansson david@loudthinking.com writes:

Class variables are like global variables whose scope is limited to
the inheritance tree.

It would be nice to have variables like global variables limited to
all instances of a class but not inherited, too.

Why? The classic Factory model used to justify class variables:
Each car that rolls off the production line has a unique number. If
we could have class instance variabless then we could inherit the
numbering code, but reuse the numbers for different models of car.

I have run into this because I’m working on a loans
system, and each item needs a unique id, which I’ve allocated as an
error correcting code. This gives me 46000 items. But if I have to
use the same class variable to number my users uniquely as well as
the items they borrow, that uses up space in my limited range.

Maybe in accordance with Ruby philosophy “theres a better way to do
it”. If so I’d welcome ideas. For now, I’m violating Don’t Repeat
Yourself. (ouch!)

  					matz.
    Hugh
···

On Fri, 22 Aug 2003, Yukihiro Matsumoto wrote:

Gawnsoft wrote:

A class-instance variable is one in which the scope is specific to a
given (sub)class.

Am I correct in dimly recalling that Ruby has support for
class-instance variables?

You are correct. If you search the ruby-talk archives you’ll find a
discussion almost the same as this
one. Bottom line was that you have to do something like this:

class Foo
def initialize
class << Foo
@class_instance_var = ‘c’
end
end

def test
    class << Foo
        puts @class_instance_var
    end
end

end

class Bar < Foo
def initialize
class << Bar
@class_instance_var = 55
end
end

def inc
    class << Bar
        @class_instance_var += 1
    end
end

def test
    class << Bar
        puts @class_instance_var
    end
end

end

foo1 = Foo.new
bar1 = Bar.new
bar2 = Bar.new

foo1.test
bar1.test
bar2.test

bar1.inc

bar1.test
bar2.test

This prints:

c
55
55
56
56

I have run into this because I’m working on a loans
system, and each item needs a unique id, which I’ve allocated as an
error correcting code. This gives me 46000 items. But if I have to
use the same class variable to number my users uniquely as well as
the items they borrow, that uses up space in my limited range.

Um, this screams “instance variables” to me…

What does your class represent, a user or a loan?

-Kurt

Hi,

···

In message “Re: Class variables - a surprising result” on 03/08/22, Hugh Sasse Staff Elec Eng hgs@dmu.ac.uk writes:

It would be nice to have variables like global variables limited to
all instances of a class but not inherited, too.

I think it can be done by self.class trick given by Robert Feldt in
[ruby-talk:79783].

						matz.

I have run into this because I’m working on a loans
system, and each item needs a unique id, which I’ve allocated as an
error correcting code. This gives me 46000 items. But if I have to
use the same class variable to number my users uniquely as well as
the items they borrow, that uses up space in my limited range.

Um, this screams “instance variables” to me…

Each has an instance var holding its number. Somewhere I must keep
the next available number, in such a way that the new item gets a
different one.

Now I’ve put it in those terms I might be better having a factory
class which has an instance var for the number, and calls the
constructor for the object I want numbered with that fresh
number…

... Item.new(@next_free) ...

Why didn’t I think of that before? Keep the number somewhere else
than the class I want to count.

What does your class represent, a user or a loan?

I have users, loans, and items to be loaned. The loans aren’t
numberd, just the users and items.

-Kurt

    Hugh
···

On Fri, 22 Aug 2003, Kurt M. Dresner wrote:

Hi,

It would be nice to have variables like global variables limited to
all instances of a class but not inherited, too.

I think it can be done by self.class trick given by Robert Feldt in
[ruby-talk:79783].

Yes, I saw that, but don’t understand it yet. I am reminded that I
still have much to learn… Elegance, simplicity and yet great
power and subtlety – what a language! Thank you.

  					matz.
    Hugh
···

On Fri, 22 Aug 2003, Yukihiro Matsumoto wrote:

In message “Re: Class variables - a surprising result” > on 03/08/22, Hugh Sasse Staff Elec Eng hgs@dmu.ac.uk writes: