[newby] class variables and class instance variable?

L

Lionel Thiry

Hello.

class Test
@a = "value"

def self.a
@a
end

def initialize
@@a = "value2"
end

def a
@@a
end
end

puts Test.a # output: value
puts Test.new.a # output: value2

I don't understand (and I'm quite surprised), what is the difference in terms of
OO design between class variables, the @@a in the example above, and class
instance variables, the @a in the example?

Thanks in advance,
Lionel Thiry
 
F

Florian Gross

Lionel said:
class Test
@a = "value"

def self.a
@a
end

def initialize
@@a = "value2"
end

def a
@@a
end
end

puts Test.a # output: value
puts Test.new.a # output: value2

I don't understand (and I'm quite surprised), what is the difference in
terms of OO design between class variables, the @@a in the example
above, and class instance variables, the @a in the example?

Currently class variables are also shared between different classes that
are part of the same inheritance tree. IMHO this is a rarely needed
feature and you're better off using regular instance variables on the
class (and referring to them via self.class.var from an instance).
 
L

Lionel Thiry

Florian said:
Lionel Thiry wrote:


Currently class variables are also shared between different classes that
are part of the same inheritance tree.
I ignored that. *doing some testing* My! You're right.
IMHO this is a rarely needed
feature and you're better off using regular instance variables on the
class (and referring to them via self.class.var from an instance).

I totally agree.

Thanks a lot,
Lionel Thiry
 
W

Wolfgang Nádasi-Donner

--
Wolfgang Nádasi-Donner
(e-mail address removed)
Lionel Thiry said:
Hello.

class Test
@a = "value"

def self.a
@a
end

def initialize
@@a = "value2"
end

def a
@@a
end
end

puts Test.a # output: value
puts Test.new.a # output: value2

I don't understand (and I'm quite surprised), what is the difference in terms of
OO design between class variables, the @@a in the example above, and class
instance variables, the @a in the example?

Thanks in advance,
Lionel Thiry

The class variable ("@@") belongs to the class object, while the instance
variable (@) belongs to the instanciated object. A short example. May be you
want to count how many objects are created based on a class. If you want to
avoid global variables ($), which is a very good decision, you can use class
variables. Using instance variables will not work.
class Mytest
@@n_of_Mytest = 0
def initialize
@@n_of_Mytest += 1
end
def Mytest.n_of_Mytest
@@n_of_Mytest
end
end

puts Mytest.n_of_Mytest
a = Mytest.new
puts Mytest.n_of_Mytest
b = Mytest.new
c = Mytest.new
puts Mytest.n_of_Mytest
d = Mytest.new
e = Mytest.new
f = Mytest.new
puts Mytest.n_of_Mytest

O.K.?
 
T

ts

W> class Mytest
W> @@n_of_Mytest = 0

svg% cat b.rb
#!/usr/local/bin/ruby
class Mytest
@n_of_Mytest = 0

def initialize
self.class.instance_eval { @n_of_Mytest += 1}
end

def Mytest.n_of_Mytest
@n_of_Mytest
end
end

puts Mytest.n_of_Mytest
a = Mytest.new
puts Mytest.n_of_Mytest
b = Mytest.new
c = Mytest.new
puts Mytest.n_of_Mytest
d = Mytest.new
e = Mytest.new
f = Mytest.new
puts Mytest.n_of_Mytest
svg%

svg% b.rb
0
1
3
6
svg%
 
F

Florian Gross

Wolfgang said:
The class variable ("@@") belongs to the class object, while the instance
variable (@) belongs to the instanciated object. A short example. May be you
want to count how many objects are created based on a class. If you want to
avoid global variables ($), which is a very good decision, you can use class
variables. Using instance variables will not work.

It will. Note that the poster said "class instance variable" which is
the instance variable of a Class. Classes are instances of Class and
Class inherits from Module which inherits from Object so classes are
objects as well:

class Foo
@counter = 0
class << self
attr_accessor :counter
end

def initialize()
self.class.counter += 1
end
end

Foo.counter # => 0
5.times { Foo.new }
Foo.counter # => 5
 
W

Wolfgang Nádasi-Donner

--
Wolfgang Nádasi-Donner
(e-mail address removed)
Florian Gross said:
It will. Note that the poster said "class instance variable" which is

*****************************************************
Ooops - need new glasses, I believe ;-) - Forget my example, please.
I often switch between Ruby an C#. This results in some confusion.
*****************************************************
 
L

Lionel Thiry

Example >>>>>
class Mytest
@@n_of_Mytest = 0
def initialize
@@n_of_Mytest += 1
end
def Mytest.n_of_Mytest
@@n_of_Mytest
end
end

puts Mytest.n_of_Mytest
a = Mytest.new
puts Mytest.n_of_Mytest
b = Mytest.new
c = Mytest.new
puts Mytest.n_of_Mytest
d = Mytest.new
e = Mytest.new
f = Mytest.new
puts Mytest.n_of_Mytest



O.K.?

I've tested your code and I've been surprised that it actually worked. If I
correctly understand the mechanism, it's like the class object and its instances
are able to access class variables through '@@'. Undubitably, I know now why I
couldn't get along with that feature.

Honestly, I largely prefer to think of classes as objects and use the class
instance variables when I want to share variables between instances. Using '@@'
doesn't seem reliable for me, as IMHO it violates some important OO principles,
the kind that if not followed leads to very embarrassing problems.

Thanks for your help,
Lionel Thiry
 
W

Wolfgang Nádasi-Donner

--
Wolfgang Nádasi-Donner
(e-mail address removed)
Florian Gross said:
Currently class variables are also shared between different classes that
are part of the same inheritance tree. IMHO this is a rarely needed
feature and you're better off using regular instance variables on the
class (and referring to them via self.class.var from an instance).

Where is this described? - It is dangerous if one doesn't know this.
class Animal
@@born = 0
def initialize
@@born += 1
puts "a new animal"
end
def Animal.born
@@born
end
end

class Dog<Animal
@@born = 0
def initialize
@@born += 1
puts "a new dog"
end
def Dog.born
@@born
end
end

class Cat<Animal
@@born = 0
def initialize
@@born += 1
puts "a new cat"
end
def Cat.born
@@born
end
end

print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
2.times{Dog.new}
print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
3.times{Cat.new}
print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"0 cats, 0 dogs, 0 animals
a new dog
a new dog
2 cats, 2 dogs, 2 animals
a new cat
a new cat
a new cat
5 cats, 5 dogs, 5 animals
 
T

ts

W> 0 cats, 0 dogs, 0 animals
W> a new dog
W> a new dog
W> 2 cats, 2 dogs, 2 animals
W> a new cat
W> a new cat
W> a new cat
W> 5 cats, 5 dogs, 5 animals
With this version of ruby

uln% ruby -v
ruby 1.9.0 (2005-03-14) [x86_64-linux]
uln%

The result is

0 cats, 0 dogs, 0 animals
a new dog
a new dog
0 cats, 2 dogs, 0 animals
a new cat
a new cat
a new cat
3 cats, 2 dogs, 0 animals
 
F

Florian Gross

ts said:
With this version of ruby

uln% ruby -v
ruby 1.9.0 (2005-03-14) [x86_64-linux]
uln%

The result is

0 cats, 0 dogs, 0 animals
a new dog
a new dog
0 cats, 2 dogs, 0 animals
a new cat
a new cat
a new cat
3 cats, 2 dogs, 0 animals

So the behavior has been changed to lookup by surrounding module/class
on method definition time?
 
L

Lionel Thiry

Hello again!

I've refactored a bit the code of Wolfgang. Now, it do a lot of reuse through
inheretance. I'm really curious to know what this refactored code would give
under ruby 1.9.0. Would you mind to test it for me, please?

Here it is:

class Animal
@@born = 0
def initialize
@@born += 1
self.class.anew
end
def self.anew
puts "a new animal"
end
def self.born
@@born
end
end

class Dog<Animal
def self.anew
puts "a new dog"
end
end

class Cat<Animal
def self.anew
puts "a new cat"
end
end

print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
2.times{Dog.new}
print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
3.times{Cat.new}
print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"

It still gives the same output:
0 cats, 0 dogs, 0 animals

a new dog

a new dog

2 cats, 2 dogs, 2 animals

a new cat

a new cat

a new cat

5 cats, 5 dogs, 5 animals


Thanks in advance,
Lionel Thiry
W> 0 cats, 0 dogs, 0 animals
W> a new dog
W> a new dog
W> 2 cats, 2 dogs, 2 animals
W> a new cat
W> a new cat
W> a new cat
W> 5 cats, 5 dogs, 5 animals


With this version of ruby

uln% ruby -v
ruby 1.9.0 (2005-03-14) [x86_64-linux]
uln%

The result is

0 cats, 0 dogs, 0 animals
a new dog
a new dog
0 cats, 2 dogs, 0 animals
a new cat
a new cat
a new cat
3 cats, 2 dogs, 0 animals
 
T

ts

L> It still gives the same output:
L> 0 cats, 0 dogs, 0 animals
L> a new dog
L> a new dog
L> 2 cats, 2 dogs, 2 animals
L> a new cat
L> a new cat
L> a new cat
L> 5 cats, 5 dogs, 5 animals

with 1.9.0

0 cats, 0 dogs, 0 animals
a new dog
a new dog
2 cats, 2 dogs, 2 animals
a new cat
a new cat
a new cat
5 cats, 5 dogs, 5 animals
 
L

Lionel Thiry

ts said:
L> It still gives the same output:
L> 0 cats, 0 dogs, 0 animals
L> a new dog
L> a new dog
L> 2 cats, 2 dogs, 2 animals
L> a new cat
L> a new cat
L> a new cat
L> 5 cats, 5 dogs, 5 animals

with 1.9.0

0 cats, 0 dogs, 0 animals
a new dog
a new dog
2 cats, 2 dogs, 2 animals
a new cat
a new cat
a new cat
5 cats, 5 dogs, 5 animals
Thanks a lot! :)

I expected it would give an error or the same output as the original code when
executed in ruby 1.9.0.

Would those modifications "correct" its behavior? (I hope I'm not too annoying
asking to test code for me)

class Dog<Animal
@@born = 0
def self.anew
puts "a new dog"
end
end

class Cat<Animal
@@born = 0
def self.anew
puts "a new cat"
end
end

Thanks in advance,
Lionel Thiry
 
T

ts

L> Would those modifications "correct" its behavior? (I hope I'm not too
L> annoying asking to test code for me)

no it does the same

0 cats, 0 dogs, 0 animals
a new dog
a new dog
2 cats, 2 dogs, 2 animals
a new cat
a new cat
a new cat
5 cats, 5 dogs, 5 animals

you are still accessing the class variable in Animal
 
W

Wolfgang Nádasi-Donner

--
Wolfgang Nádasi-Donner
(e-mail address removed)
Lionel Thiry said:
I've tested your code and I've been surprised that it actually worked. If I
correctly understand the mechanism, it's like the class object and its instances
are able to access class variables through '@@'. Undubitably, I know now why I
couldn't get along with that feature.

Honestly, I largely prefer to think of classes as objects and use the class
instance variables when I want to share variables between instances. Using '@@'
doesn't seem reliable for me, as IMHO it violates some important OO principles,
the kind that if not followed leads to very embarrassing problems.

Thanks for your help,
Lionel Thiry

I think "@@" was based on Perl, where combinations of special characters
have (very very) special meanings.

The problem would be solved easily (I hope) with some kind of syntax like:

class Mytest
@@n_of_Mytest = 0
def initialize
Mytest.@@n_of_Mytest += 1
end
def Mytest.n_of_Mytest
@@n_of_Mytest
end
end

.... if the "@@"-notation will be stable (should be somehow, because all
books for beginners will refer to).
 
R

Randy Kramer

(Sorry for the top posting.)

I'd like to take a shot at answering Lionel's original question (what is the
difference between class and instance variables). It seems convenient to use
the result of Guy Decoux's example as an example.

If you use class and instance variables "properly", you can achieve the
following result, which can be very useful in some cases. Note that instance
variables in the dog and cat class count the dogs and cats respectively,
while the class variable (in the animal class) counts the animals (i.e., dogs
+ cats):

0 cats, 0 dogs, 0 animals
a new dog
a new dog
0 cats, 2 dogs, 2 animals
a new cat
a new cat
a new cat
3 cats, 2 dogs, 5 animals

I am a newbie to Ruby, my answer is based on what I understand should happen
with instance and class variables.

regards,
Randy Kramer
 
R

Randy Kramer

Oops, I need to correct myself:

If you use class and instance variables "properly", you can achieve the
following result, which can be very useful in some cases. Note that
instance variables in the dog and cat class count the dogs and cats

In the previous line, it would have been more clear (and correct ;-) to say
"in the dog and cat *instances* (of the animal class)"

respectively, while the class variable (in the animal class) counts the
animals (i.e., dogs + cats):

Randy Kramer
 
L

Lionel Thiry

Randy said:
(Sorry for the top posting.)

I'd like to take a shot at answering Lionel's original question (what is the
difference between class and instance variables).
Oops, there is some confusion here: "class variable", "class instance variable"
and "instance variable" are three different things.

@a in the context of instance code is an instance variable. "instance variable"
is contained in an object, any object. As being internal to the object, it
cannot be accessed from outside without a method call.

Code example:
class MyClass
def initialize # instance method
# instance code
@a = "value"
end
def a
@a
end
end
puts MyClass.new.a # output: value

@a in the context of class code is a "class instance variable". "class instance
variable" is contained in an object, but not any one, it is contained in a
class, as classes are objects too. Then, as being internal to the class object,
it cannot be accessed from outside without a class method call.

Code example:
class MyClass
#class code
@a = "value"
def self.a # class method
# class code
@a
end
def a # instance method
# instance code
@a
end
end
puts MyClass.a # output: value
puts MyClass.new.a # output: nil

@@a whatever the context is a "class variable". "class variable" is "contained"
in a class as if it was a "class instance variable" but without being one, it
exists in "another world". In practical terms, the main difference is that '@@'
is reachable from any instance without passing through any method call (which
IMHO is poor OO design).

Code example:
class MyClass
# class code
@@a = 0
def incr # instance method
# instance code
@@a += 1
end
def a # instance method
# instance code
@@a
end
def self.incr # class method
# class code
@@a += 1
end
def self.a # class method
# class code
@@a
end
end
my_instance = MyClass.new
other_instance = MyClass.new
puts MyClass.a # output: 0
puts my_instance.a # output: 0
puts other_instance.a # output: 0
my_instance.incr
puts MyClass.a # output: 1
puts my_instance.a # output: 1
puts other_instance.a # output: 1
other_instance.incr
puts MyClass.a # output: 2
puts my_instance.a # output: 2
puts other_instance.a # output: 2
MyClass.incr
puts MyClass.a # output: 3
puts my_instance.a # output: 3
puts other_instance.a # output: 3

Is it ok?

Now, there is worse. @@a var is shared not only between the class and and its
instances, but also with all inheriting classes and all their instances!

Guy Decoux showed things are different in 1.9.0, but I don't understand how it
works.
 
R

Randy Kramer

Oops, there is some confusion here: "class variable", "class instance
variable" and "instance variable" are three different things.

Ok, thanks! I think I've got the general idea--a class variable and class
instance variable are almost the same, except the class variable is sort of a
"renegade" global type of thing.

Any more than that I'll probably have to let develop as this stuff soaks in a
little more. ;-)

Randy Kramer

---<good stuff snipped>---
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top