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

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

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.

···

On Tue, Sep 18, 2012 at 12:07 PM, Aleksander Ciesielski <neomex@onet.eu> wrote:

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);
  }

}

···

--
Posted via http://www.ruby-forum.com/.

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

···

On Tue, Sep 18, 2012 at 12:07 PM, Aleksander Ciesielski <neomex@onet.eu> wrote:

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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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
  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 method `each' 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 provate class varibale. Surely
this must be possible?

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

···

--
Posted via http://www.ruby-forum.com/.

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

···

--
Posted via http://www.ruby-forum.com/.

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 method `secret_val' for
#<Dog:0x00000100925be8 @secret_val=10> (NoMethodError)

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

--output:--
10

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

--output:--
10

--output:--
10

···

--
Posted via http://www.ruby-forum.com/\.

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

···

--
Posted via http://www.ruby-forum.com/.

@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.

···

--
Posted via http://www.ruby-forum.com/.

Thank you very much for all your replies.
I think I did 2 things wrong:

1) I used new, rather than initialize
2) I thougt 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
<snip>
--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?

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

···

--
Posted via http://www.ruby-forum.com/.

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?

···

--
Posted via http://www.ruby-forum.com/\.

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).

···

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

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 method `each' 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 provate class varibale. Surely
this must be possible?

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

--
Posted via http://www.ruby-forum.com/\.

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.

···

--
Posted via http://www.ruby-forum.com/\.

--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
<snip>
--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?

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 ( Class and Instance Variables In Ruby // RailsTips by John Nunemaker ) gives a really nice explanation of the topic.

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.

···

On 09/19/2012 03:03 PM, Jeroen Lodewijks wrote:

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?

--
Lars Haugseth

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

···

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

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

--
Lars Haugseth

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.