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
Is it obligatory to use instance variables in classes? Can't we just write
something like this:class Test
var = 5def show
puts var
end
endtest = 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 = 5def show
puts var
end
endtest = 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
--
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 :hcpdef new(value, suit)
@value = value
@suit = suit
enddef hcp()
return @hcp
end
endclass 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
enddef 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
enddef remove_card
return @deck.pop
enddef print_all
@deck.each do |card|
puts card.suit
puts card.value
end
endrequire '.\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
--
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_varend
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 = 5def show
puts var
enddef set(value)
var = value
end
endtest1 = Test.new
test1.set 10test2 = Test.new
test2.set 20test1.show
test2.showShould 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.