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

CCC

I think I know whats going on.

When a variable is first used, that is where it is
declared. Unlike Java there is no separate
declaration. If you like, declaration is automatic
when the variable is first reference.

So Sup is declared. Class variable @@x is referenced
and associated with Sup.

Sup1 is declared. @@x is referenced. @@x is not
found in the current class, so super.@@x is
referenced.
@@x is found, and updated.

Note thae @@x = “B” is part of the classes
declaration, and so will always be invoked, and that
the ‘message’ will be passed back to Sup, thus
updating the value of @@x in Sup.

Same thing happens all over again in Sup2.

Here is the code to get the desired result.

class Sup
@@x = nil
writer: @@x
def initialize
@@x = “A”
end
def test
print @@x
end
end

class Sub1 < Sup
def initialize
@@x = “B”
end
end

class Sub2 < Sup
def initialize
@@x = “C”
end
end

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

ABC

However, things still don’t work out right if we
assign to variables first. Replace the last three
lines with:

s = Sup.new
s1a = Sub1.new
s1b = Sub1.new
s2a = Sub2.new
s2b = Sub2.new

s.test
s1a.test
s1b.test
s2a.test
s2b.test

CCC

Is this suprising? Perhaps not, here is the
equivalent Java code:

class sup {
static char x = ‘A’;
void test() {
System.out.print(x);
}
}

class sup1 extends sup {
{ x = ‘B’; }
}

class sup2 extends sup {
{ x = ‘C’; }
}

CCC

The original scenario cannot be replicated in Java
because a class is loaded and initialised at first
use, rather than at declaration.

class sup {
static char x;
sup() {
x = ‘A’;
}
void test() {
System.out.print(x);
}
}

class sup1 extends sup {
static char x;
sup1() {
x = ‘B’;
}
void test() {
System.out.print(x);
}
}

class sup2 extends sup {
static char x;
sup2() {
x = ‘C’;
}
void test() {
System.out.print(x);
}
}

I can’t find any cleaner way to do this in Java.
Remove either the duplicate declaration of x or test()
and your back to the original problem.

So whats the best approach in ruby? To keep a class
hash that contains a value associated with each class?

···

Want to chat instantly with your online friends? Get the FREE Yahoo!
Messenger http://uk.messenger.yahoo.com/

Hi –

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

CCC

I think I know whats going on.

When a variable is first used, that is where it is
declared. Unlike Java there is no separate
declaration. If you like, declaration is automatic
when the variable is first reference.

So Sup is declared. Class variable @@x is referenced
and associated with Sup.

Sup1 is declared. @@x is referenced. @@x is not
found in the current class, so super.@@x is
referenced.
@@x is found, and updated.

I think it’s simpler than that: you’re just assigning to a variable.
It’s like:

x = “A”

x = “B”

@@x is simply the same variable both times – that’s how it’s scoped.

Note thae @@x = “B” is part of the classes
declaration, and so will always be invoked, and that
the ‘message’ will be passed back to Sup, thus
updating the value of @@x in Sup.

Same thing happens all over again in Sup2.

Here is the code to get the desired result.

class Sup
@@x = nil
writer: @@x

There no such thing:

$ ruby cvars.rb
cvars.rb:3: syntax error
writer: @@x
^

[…]

So whats the best approach in ruby? To keep a class
hash that contains a value associated with each class?

Over on IRC (irc.freenode.net, channel #ruby-lang) we’ve just
been chatting about class instance variables, which are the
best way to achieve true per-class state maintenance. They’ve
been talked about here a number of times; you can search on
www.ruby-talk.org or Google. Or join us on IRC :slight_smile:

David

···

On Thu, 21 Aug 2003, [iso-8859-1] Ged Byrne wrote:


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

I think it’s simpler than that: you’re just
assigning to a variable.

It’s probably is simpler. I’m afraid I’m still
thinking in Java.

There no such thing:

$ ruby cvars.rb
cvars.rb:3: syntax error
writer: @@x
^

[…]
Ooops, need to be more careful undoing after my
experiments. Delete the writer: @@x line for the code
to work.

So whats the best approach in ruby? To keep a
class
hash that contains a value associated with each
class?

Over on IRC (irc.freenode.net, channel #ruby-lang)
we’ve just
been chatting about class instance variables, which
are the
best way to achieve true per-class state
maintenance. They’ve
been talked about here a number of times; you can
search on
www.ruby-talk.org or Google. Or join us on IRC :slight_smile:

Thanks, I’m off to google. Wish IRC was an option :frowning:

David


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Ged.

···

Want to chat instantly with your online friends? Get the FREE Yahoo!
Messenger http://uk.messenger.yahoo.com/

Try:

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

class Sub1 < Sup
@x = "B"
end

class Sub2 < Sup
@x = "C"
end

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

Not the simplest but…

/Robert