Class variables

Is it obligatory to use instance variables in classes? Can’t we just
write something like this:

class Test
var = 5

 def show
     puts var
 end

end

test = Test.new
test.show
p test.var

On Tue, Sep 18, 2012 at 12:07 PM, Aleksander C. [email protected]
wrote:

test = Test.new
test.show
p test.var

This doesn’t work. The keyword def starts a new scope, so the “var”
inside “show” is a different local variable than the var in the scope
of the class. Even if this weren’t the case, this would resemble more
a class instance variable than an instance variable, since all
instances of the class would have the same value for “var”. By the
way, you can achieve this using “define_method” instead of “def”,
since define_method is a closure and can see the surrounding scope:

1.9.2p290 :012 > class Test
1.9.2p290 :013?> var = 5
1.9.2p290 :014?> define_method :show do
1.9.2p290 :015 > puts var
1.9.2p290 :016?> end
1.9.2p290 :017?> end
=> #<Proc:0x00000000b54938@(irb):14 (lambda)>
1.9.2p290 :018 > Test.new.show
5
=> nil

But as I said, all instances see the same value:

1.9.2p290 :019 > a = Test.new
=> #Test:0x00000000b42f08
1.9.2p290 :020 > b = Test.new
=> #Test:0x00000000b3ac90
1.9.2p290 :021 > a.show
5
=> nil
1.9.2p290 :022 > b.show
5
=> nil

and you cannot change it on a per instance case. That’s what instance
variables are for.
The last part

p test.var

can never work, since you don’t define a method called var.

Jesus.

Hi,

I think the main problem here is that you somehow try to apply the
concepts of another language to Ruby.

Ruby isn’t Java (or whatever it is you use). It doesn’t have
“attributes” in the sense of object variables you can set in the class
body and access directly from the outside.

class Test {

int var = 5;

void show() {
System.out.println(var);
}

}

On Tue, Sep 18, 2012 at 12:07 PM, Aleksander C. [email protected]
wrote:

test = Test.new
test.show
p test.var

You can do that. But it probably does not lead to the result you are
expecting / wanting.

What is it that you want to achieve?

Cheers

robert

Jan E. wrote in post #1076455:

class Test {

int var = 5;

void show() {
System.out.println(var);
}

}

Hi all,

This is exactly the question that I also wanted to ask, being new to
Ruby. I just registered 5 min ago and see almost the first post is the
very same probem.

What I want to do achieve is: I want a variable known throughout the
scope of the class but that is not always the same variable if you
instanciate a new object of the class (I like to achieve what the java
code above does).

For instance:

class Test
var = 5

 def show
     puts var
 end

 def set(value)
     var = value
 end

end

test1 = Test.new
test1.set 10

test2 = Test.new
test2.set 20

test1.show
test2.show

Should show 10 and 20

How do I do this?

On 09/19/2012 03:03 PM, Jeroen L. wrote:

}
code above does).
def set(value)
test1.show
test2.show

Should show 10 and 20

How do I do this?

class Test
attr_accessor :var

def initialize
@var = 5
end
end

test1 = Test.new
test1.var = 10

test2 = Test.new
test2.var = 20

test3 = Test.new

puts test1.var # => 10
puts test2.var # => 20
puts test3.var # => 5

The attr_accessor statement creates the var= and var methods for setting
and getting the value of the @var instance variable. You can set it to
some default value for new instances in the initialize method.

Thanks for the answer.

The problem with this code is that this variable is accessible from
outside.
Let me elaborate what I tried to do. I have code like this:
(Not saying this is good code, I a messing around at the moment)

class Card
attr_accessor :suit
attr_accessor :value
attr_accessor :name
attr_accessor :picture
attr_accessor :hcp

def new(value, suit)
@value = value
@suit = suit
end

def hcp()
return @hcp
end
end

class Deck
require ‘.\Card’
@deck = []
@@suits = [‘C’, ‘D’, ‘H’, ‘S’]
@@values = [‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘10’, ‘J’, ‘Q’,
‘K’, ‘A’]

def new(passes = 7)
@@suits.each do |suit|
@@values.each do |value|
@deck.push = Card.new(suit, value)
end
end
shuffle(passes)

return @deck

end

def shuffle(no_of_times)
max_len = @deck.length
no_of_times.each do
for source in (no_of_time…source)
target = rand(source+1)
@deck[source], @deck[target] = @deck[target], @deck[source]
end
end
end

def remove_card
return @deck.pop
end

def print_all
@deck.each do |card|
puts card.suit
puts card.value
end
end

require ‘.\Deck.rb’

@deck = Deck.new()
@deck.print_all()

When I execute this I get the error:
in print_all': undefined methodeach’ for nil:NilClass (NoMethodError)

This is exactly the behaviour as described above by OP. I understand why
now. The variable is not in scope. But how do I create a ‘local’
variable (in my case deck) that can be seen by all methods of the class
but not be manipulated from outside?
Sorry for this basic question but all courses on Ruby classes that I
could find online, not one example had a private class variable. Surely
this must be possible?

PS funny that a couple of threads below, the post is about card tricks
:slight_smile:

On Sep 19, 2012, at 10:29 AM, Jeroen L. wrote:

Thanks for the answer.

The problem with this code is that this variable is accessible from
outside.
Let me elaborate what I tried to do. I have code like this:
(Not saying this good code, I a messing around at the moment)

class Card
attr_accessor :suit

This is just “shorthand” for:

def suit
@suit
end
def suit=(value)
@suit = value
end

If you want these instance variables internal, just don’t create the
accessors for them (either implicily or explicitly).

Meaby it is good for you to know that also exist: attr_reader and
attr_writer. First one just create a “reader method” of the instance
variable passed as argument to attr_reader, second one just let you
change the instance variable passed as argument to attr_writer, not read
it.

class Foo
attr_reader :x
attr_writer :y
def initialize
@x = rand
@y = rand
end
end

Same as…

class Foo
def initialize
@x = rand
@y = rand
end
def x
@x
end
def y=(value)
@y = value
end
end

The problem with this code is that this variable is accessible from
outside.

Check this out:

class Dog
def initialize
@secret_val = 10
end
end

d = Dog.new
puts d.secret_val

–output:–
1.rb:9:in <main>': undefined methodsecret_val’ for
#<Dog:0x00000100925be8 @secret_val=10> (NoMethodError)

Hey, it looks like @secret_val is equal to 10 in that error message.
I wonder if I can confirm that:

x = d.instance_eval("@secret_val")
puts x

–output:–
10

x = d.send(:instance_variable_get, “@secret_val”)
puts x

–output:–
10

class Card
attr_accessor :suit
attr_accessor :value
attr_accessor :name
attr_accessor :picture
attr_accessor :hcp

Those are all method calls. Do this instead:

attr_accessor :suit, :value, :name, :picture, :hcp

Don’t do this:

def new(value, suit)
@value = value
@suit = suit
end

Do this instead:

def initialize(value, suit)
@value = value
@suite = suit
end

obj = MyClass.new(3, ‘diamonds’)

Return statements aren’t used so much in ruby because a method returns
the result of the last statement that was evaluated. So don’t do this:

def hcp()
return @hcp
end

Do this:

def hcp
@hcp
end

However, calling attr_accessor :hcp is equivalent to writing the
following in your class:

def hcp
@hcp
end

def hcp=(val)
@hcp = val
end

The implementation of class variables in ruby:

@@suits = [‘C’, ‘D’, ‘H’, ‘S’]

isn’t what you would expect, so no one uses them. Rubyists use class
instance variables instead, e.g.

class Dog
@my_var

end

The implementation of class variables in ruby …
isn’t what you would expect, so no one uses them.

I use them all the time !

Rubyists use class instance variables instead, e.g.

class Dog
@my_var

end

Explain please.

@original poster:

Test is a standard Ruby Library module, and test() is an important
global method (defined in module Kernel.)

Train yourself to use other identifiers.

Thank you very much for all your replies.
I think I did (at least :slight_smile: ) 2 things wrong:

  1. I used new, rather than initialize
  2. I thought the syntax for a class variable was

class Deck
@deckarr = [1, 2, 3, 4, 5]

def initialize
# something
end

def print_all
@deckarr.each do |card| puts card end
end
end

but it is:

class Deck

def initialize
@deckarr = [1, 2, 3, 4, 5]
end

def print_all
@deckarr.each do |card| puts card end
end
end

–Quote
@@suits = [‘C’, ‘D’, ‘H’, ‘S’]

isn’t what you would expect, so no one uses them. Rubyists use class
instance variables instead, e.g

–End quote

From what I can see online
@@suits = [‘C’, ‘D’, ‘H’, ‘S’] creates the array only once no matter how
many instances you have of the object. Is that not a good thing?
I don’t understand why nobody is using this?

On 09/21/2012 03:02 PM, Calvin Bornhofen wrote:

class Foo
class << self; attr_accessor :suits end
@suits = [‘C’, ‘D’, ‘H’, ‘S’]
end

How about:

class Foo
def self.suits
@suits ||= %w(C D H S)
end
end

or even just

class Foo
def self.suits
%w(C D H S)
end
end

many instances you have of the object. Is that not a good thing?
I don’t understand why nobody is using this?

isn’t what you would expect, so no one uses them. Rubyists use class
instance variables instead, e.g.
The @@ makes the variable a static-like variable as you know it from
other OO-languages. The thing is, that this variable is not a static
member of the class in the usual sense. It is consistent over the whole
class hierarchy. So, if you change the value in one subclass, you change
it for all classes. Sometimes that is what you want to have, but usually
it is not. But, Ruby has an alternative: Since classes are also objects,
you can declare a variable on the class level by using @ instead of @@.
This makes the variable available to your class, and all subclasses,
but makes it a different variable for each class. Next question is,
how do you access them? The usual attr_* methods don’t work, since they
add the methods to the instance level. So, what we could do, is to write
the accessors on our own ( by defining methods like self.myvariable
and/or self.myvariable= ). But Ruby wouldn’t be Ruby if that wouldn’t be
easier:

class Foo
class << self; attr_accessor :suits end
@suits = [‘C’, ‘D’, ‘H’, ‘S’]
end

The construct “class << self; […] end” makes all it’s contents apply
on the class level, not the instance level ( you may have seen it in
tutorials you read ). That’s all the magic.
Of course, you could use @@ as you are doing it currently, but you
should be aware of the implications of that.

FYI: I think this page (
http://railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/
) gives a really nice explanation of the topic.

How about:

class Foo
def self.suits
@suits ||= %w(C D H S)
end
end

Works too. If you just wanted to read the variable or perform actions
with it, that is definitely shorter.

or even just

class Foo
def self.suits
%w(C D H S)
end
end
Looks similar, but it has one flaw: The array is created every time
again the method is called ( checked via object_id - it differs every
time the method is called ). Might not make a difference in this
scenario, but if you wanted to modify the array, your changes wouldn’t
persist. So that’s something to be aware of. It can also be a
performance problem if the array gets more complex, I think.