Ruby- read the value of a variable in another class? - ruby

I have something like the following
class A
def initialize
#var = 0
end
def dosomething
#var+=1
end
end
class B < A
def initialize
super
end
def func
puts #var
end
end
The problem is when I call
a = A.new
a.dosomething
b = B.new
the value which #var returns is 0 how would I change my code so it would return the "new" value of var (1)?

Quick answer, for if you actually understand Classes, Inheritance and Objects : replace #var (an instance variable, and therefore different in a and b) with ##var (a class variable, and therefore the same in all instances of class A).
Otherwise, your question indicates you have a fundamental misunderstanding of what's going on with classes, objects and inheritance.
Your code does the following:
Defines a class, called A. This is essentially a blueprint from which you can create objects.
Declares that when an object of type A is created, that object should be given it's own private copy of an attribute, called var, which is set to 0.
Declares that objects of type A can be asked to dosomething, which increases the value of that object's var by 1.
Defines a class called B, which is a special case of an A
Therefore, in your second snippet, you create an object a, which is an A. It has its own attribute called var, which is set to 0 and then incremented. You then create b, which is a B (and is therefore also an A). b has its own attribute called var, separate from a's var, which is set to 0.

Variables like #var are called instance variables because they are unique to every instance of a class. You've created two separate instances, a and b, and they have their own instance variables.
You can use class variables if you want to see them in your subclass:
class A
##var = 0
def dosomething
##var += 1
end
end
class B < A
def func
puts ##var
end
end
You can also use class-level accessor methods:
class A
class << self
attr_accessor :var
def dosomething(n)
self.var = n
end
end
end
class B < A
def func
puts A.var
end
end
irb(main):031:0> A.dosomething(5)
=> 5
irb(main):032:0> b = B.new
=> #<B:0x2b349d>
irb(main):033:0> b.func
5
Note that inheritance is not needed for this to work.

You could use class variables:
class A
##var = 0
def dosomething
##var += 1
end
end
class B < A
def func
puts ##var
end
end
a = A.new
a.dosomething
a.dosomething
b = B.new
b.func # => 2

#var is an instance variable, each instance of this class has its own value of this variable. So it is correct that b does return 0, since it is a different instance compared to a.
To update the value in b use:
b = B.new
b.dosomething
Here is more information on instance variables.
Or if you want a class variable (ie a variable which is the same in all instances of that class), use ##var. Then your given example works.
Here is some more information on class variables.
Which solution you need, depends on your application.

You need to use class variables, not instance variables. Try something like this:
class A
##var = 0
def dosomething
##var+=1
end
end
class B < A
def func
puts ##var
end
end

Related

Not a class variable, but maybe an instance variable -- but on what? [duplicate]

I read https://stackoverflow.com/questions/826734/when-do-ruby-instance-variables-get-set but I'm of two minds when to use class instance variables.
Class variables are shared by all objects of a class, Instance variables belong to one object. There's not much room left to use class instance variables if we have class variables.
Could someone explain the difference between these two and when to use them?
Here's a code example:
class S
##k = 23
#s = 15
def self.s
#s
end
def self.k
##k
end
end
p S.s #15
p S.k #23
Update: I understand now! Class Instance Variables are not passed along the inheritance chain.
Instance variable on a class:
class Parent
#things = []
def self.things
#things
end
def things
self.class.things
end
end
class Child < Parent
#things = []
end
Parent.things << :car
Child.things << :doll
mom = Parent.new
dad = Parent.new
p Parent.things #=> [:car]
p Child.things #=> [:doll]
p mom.things #=> [:car]
p dad.things #=> [:car]
Class variable:
class Parent
##things = []
def self.things
##things
end
def things
##things
end
end
class Child < Parent
end
Parent.things << :car
Child.things << :doll
p Parent.things #=> [:car,:doll]
p Child.things #=> [:car,:doll]
mom = Parent.new
dad = Parent.new
son1 = Child.new
son2 = Child.new
daughter = Child.new
[ mom, dad, son1, son2, daughter ].each{ |person| p person.things }
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
With an instance variable on a class (not on an instance of that class) you can store something common to that class without having sub-classes automatically also get them (and vice-versa). With class variables, you have the convenience of not having to write self.class from an instance object, and (when desirable) you also get automatic sharing throughout the class hierarchy.
Merging these together into a single example that also covers instance variables on instances:
class Parent
##family_things = [] # Shared between class and subclasses
#shared_things = [] # Specific to this class
def self.family_things
##family_things
end
def self.shared_things
#shared_things
end
attr_accessor :my_things
def initialize
#my_things = [] # Just for me
end
def family_things
self.class.family_things
end
def shared_things
self.class.shared_things
end
end
class Child < Parent
#shared_things = []
end
And then in action:
mama = Parent.new
papa = Parent.new
joey = Child.new
suzy = Child.new
Parent.family_things << :house
papa.family_things << :vacuum
mama.shared_things << :car
papa.shared_things << :blender
papa.my_things << :quadcopter
joey.my_things << :bike
suzy.my_things << :doll
joey.shared_things << :puzzle
suzy.shared_things << :blocks
p Parent.family_things #=> [:house, :vacuum]
p Child.family_things #=> [:house, :vacuum]
p papa.family_things #=> [:house, :vacuum]
p mama.family_things #=> [:house, :vacuum]
p joey.family_things #=> [:house, :vacuum]
p suzy.family_things #=> [:house, :vacuum]
p Parent.shared_things #=> [:car, :blender]
p papa.shared_things #=> [:car, :blender]
p mama.shared_things #=> [:car, :blender]
p Child.shared_things #=> [:puzzle, :blocks]
p joey.shared_things #=> [:puzzle, :blocks]
p suzy.shared_things #=> [:puzzle, :blocks]
p papa.my_things #=> [:quadcopter]
p mama.my_things #=> []
p joey.my_things #=> [:bike]
p suzy.my_things #=> [:doll]
Source
Availability to instance methods
Class instance variables are available only to class methods and not to instance methods.
Class variables are available to both instance methods and class methods.
Inheritability
Class instance variables are lost in the inheritance chain.
Class variables are not.
class Vars
#class_ins_var = "class instance variable value" #class instance variable
##class_var = "class variable value" #class variable
def self.class_method
puts #class_ins_var
puts ##class_var
end
def instance_method
puts #class_ins_var
puts ##class_var
end
end
Vars.class_method
puts "see the difference"
obj = Vars.new
obj.instance_method
class VarsChild < Vars
end
VarsChild.class_method
I believe the main (only?) different is inheritance:
class T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
Class variables are shared by all "class instances" (i.e. subclasses), whereas class instance variables are specific to only that class. But if you never intend to extend your class, the difference is purely academic.
As others said, class variables are shared between a given class and its subclasses. Class instance variables belong to exactly one class; its subclasses are separate.
Why does this behavior exist? Well, everything in Ruby is an object—even classes. That means that each class has an object of the class Class (or rather, a subclass of Class) corresponding to it. (When you say class Foo, you're really declaring a constant Foo and assigning a class object to it.) And every Ruby object can have instance variables, so class objects can have instance variables, too.
The trouble is, instance variables on class objects don't really behave the way you usually want class variables to behave. You usually want a class variable defined in a superclass to be shared with its subclasses, but that's not how instance variables work—the subclass has its own class object, and that class object has its own instance variables. So they introduced separate class variables with the behavior you're more likely to want.
In other words, class instance variables are sort of an accident of Ruby's design. You probably shouldn't use them unless you specifically know they're what you're looking for.
Official Ruby FAQ: What is the difference between class variables and class instance variables?
The main difference is the behavior concerning inheritance: class variables are shared between a class and all its subclasses, while class instance variables only belong to one specific class.
Class variables in some way can be seen as global variables within the context of an inheritance hierarchy, with all the problems that come with global variables. For instance, a class variable might (accidentally) be reassigned by any of its subclasses, affecting all other classes:
class Woof
##sound = "woof"
def self.sound
##sound
end
end
Woof.sound # => "woof"
class LoudWoof < Woof
##sound = "WOOF"
end
LoudWoof.sound # => "WOOF"
Woof.sound # => "WOOF" (!)
Or, an ancestor class might later be reopened and changed, with possibly surprising effects:
class Foo
##var = "foo"
def self.var
##var
end
end
Foo.var # => "foo" (as expected)
class Object
##var = "object"
end
Foo.var # => "object" (!)
So, unless you exactly know what you are doing and explicitly need this kind of behavior, you better should use class instance variables.
While it may immediately seem useful to utilize class variables, since class variable are shared among subclasses and they can be referred to within both singleton and instance methods, there is a singificant drawback. They are shared and so subclasses can change the value of the class variable, and the base class will also be affected by the change, which is usually undesirable behavior:
class C
##c = 'c'
def self.c_val
##c
end
end
C.c_val
=> "c"
class D < C
end
D.instance_eval do
def change_c_val
##c = 'd'
end
end
=> :change_c_val
D.change_c_val
(irb):12: warning: class variable access from toplevel
=> "d"
C.c_val
=> "d"
Rails introduces a handy method called class_attribute. As the name implies, it declares a class-level attribute whose value is inheritable by subclasses. The class_attribute value can be accessed in both singleton and instance methods, as is the case with the class variable. However, the huge benefit with class_attribute in Rails is subclasses can change their own value and it will not impact parent class.
class C
class_attribute :c
self.c = 'c'
end
C.c
=> "c"
class D < C
end
D.c = 'd'
=> "d"
C.c
=> "c"
For those with a C++ background, you may be interested in a comparison with the C++ equivalent:
class S
{
private: // this is not quite true, in Ruby you can still access these
static int k = 23;
int s = 15;
public:
int get_s() { return s; }
static int get_k() { return k; }
};
std::cerr << S::k() << "\n";
S instance;
std::cerr << instance.s() << "\n";
std::cerr << instance.k() << "\n";
As we can see, k is a static like variable. This is 100% like a global variable, except that it's owned by the class (scoped to be correct). This makes it easier to avoid clashes between similarly named variables. Like any global variable, there is just one instance of that variable and modifying it is always visible by all.
On the other hand, s is an object specific value. Each object has its own instance of the value. In C++, you must create an instance to have access to that variable. In Ruby, the class definition is itself an instance of the class (in JavaScript, this is called a prototype), therefore you can access s from the class without additional instantiation. The class instance can be modified, but modification of s is going to be specific to each instance (each object of type S). So modifying one will not change the value in another.
Simple example showing
inheritability of class variables
encapsulation of class instance variables
NOTE: Usage of the class << self is a convenience, instead of having to prepend all the methods inside this block with self. Note: the class << self modifies self so it points to the metaclass for Parent (see https://stackoverflow.com/a/38041660/960184)
Example code
class Parent
class << self
attr_reader :class_instance_var
def class_instance_var=(value)
#class_instance_var="set by #{self.name} to #{value}"
end
def class_var
##class_var
end
def class_var=(value)
##class_var = "set by #{self.name} to #{value}"
end
end
end
class Child < Parent
end
# use the instance separately in parent and subclass
puts "\n* Exercising class instance variable setters
* Setting Parent and Child class instance variables differently
* Parent.class_instance_var = 1000\n* Child.class_instance_var = 2000\n\n"
Parent.class_instance_var = 1000
Child.class_instance_var = 2000
puts "Parent.class_instance_var=(#{Parent.class_instance_var})"
puts "Child.class_instance_var=(#{Child.class_instance_var})"
# set class variable in via parent (changes both in parent and subclass)
puts "\n* Exercising Parent class variable setter
* Set class variable value to 3000 using parent, it changes in Child also
* Parent.class_var = 3000\n\n"
Parent.class_var = 3000
puts "Parent.class_var=(#{Parent.class_var})"
puts "Child.class_var=(#{Child.class_var})"
# set class variable in via subclass (changes both in parent and subclass)
puts "\n* Exercising Child class variable setter
* Set class variable value to 5000 using child, it changes in Parent also
* Child.class_var = 5000\n\n"
Child.class_var = 5000
puts "Parent.class_var=(#{Parent.class_var})"
puts "Child.class_var=(#{Child.class_var})"
Output using ruby v3.0.2
* Exercising class instance variable setters
* Setting Parent and Child class instance variables differently
* Parent.class_instance_var = 1000
* Child.class_instance_var = 2000
Parent.class_instance_var=(set by Parent to 1000)
Child.class_instance_var=(set by Child to 2000)
* Exercising Parent class variable setter
* Set class variable value to 3000 using parent, it changes in Child also
* Parent.class_var = 3000
Parent.class_var=(set by Parent to 3000)
Child.class_var=(set by Parent to 3000)
* Exercising Child class variable setter
* Set class variable value to 5000 using child, it changes in Parent also
* Child.class_var = 5000
Parent.class_var=(set by Child to 5000)
Child.class_var=(set by Child to 5000)

Get a reference to an object while instantiating it

I'd like to reference an object while instantiating it in order to pass it to another object I'm instantiating. What I mean:
A.new(B.new(self))
In this case, self would refer to the scope in which I'm actually calling A.new. What I want is for self (or whatever other keyword) to refer to the newly instantiated A object, so that B would have a reference to A. Is there a way to do this?
The way you have written it (A.new(B.new(self))) is impossible, due to a circular reference.
In order to create an instance of A, you need an instance of B; in order to create the instance of B, you need the instance of A.
There are a few ways you tweak the implementation to make this possible, but you must first resolve this chicken-and-egg problem between the A and B. For example:
class A
def initialize
#b = yield(self)
end
end
class B
def initialize(a)
#a = a
end
end
A.new { |a| B.new(a) }
Note that in the above code, a is being initialized first. It is only being yielded in the scope after the object has been created.
Or, here's another way:
class A
def initialize
#b = B.new(self)
end
end
class B
def initialize(a)
#a = a
end
end
A.new
Like above, the instance of A is being created first. But this time, I've done all the initialization in one go rather than building it within the new() methed call.
One final example:
class A
attr_writer :b
def initialize
end
end
class B
def initialize(a)
#a = a
end
end
A.new.tap { |a| a.b = B.new(a) }
In this example, I have fully initialized a before defining its attribute of b. This could just as easily have been written in two lines of code, with a regular variable instead of the closure:
a = A.new
a.b = B.new(a)

Accessing Instance Variable Directly in Ruby?

Why can't I access an instance variable directly in ruby without using an accessor method or instance_variable_get?
class Foo
#my_var
end
Why shouldn't we be able to use Foo.#my_var in this example?
The example provided by the OP is a class instance variable. These can only be accessed by class methods.
"regular" attribute accessors won't allow access from outside the class. Here are a couple of ways to create accessors that work:
class A
#class_instance_var = "foo"
class << self
attr_accessor :class_instance_var
end
end
puts A::class_instance_var # Output: foo
OR
class A
#class_instance_var = "foo"
def self.class_instance_var
#class_instance_var
end
end
puts A::class_instance_var # Output: foo
Class instance variables
Class instance variable names also begin with #. However, they are defined at class level, outside any methods. Class instance variables can only be accessed by class methods. They are shared amongst all instances of a class but not its subclasses. In other words, they are not inheritable. If the value of a class instance variable is changed in one instance of the class, all other instances are affected. Earlier we saw how all classes are instances of a built-in class called Class. That is what makes class instance variables possible.
class Vehicle
#count = 0 # This is a class instance variable
def initialize
self.class.increment_count
self.class.show_count
end
def self.increment_count # This is a class method
#count += 1
end
def self.show_count # This is a class method
puts #count
end
end
class Car < Vehicle
#count = 0
end
v1 = Vehicle.new # Output: 1
v2 = Vehicle.new # Output: 2
v3 = Vehicle.new # Output: 3
car1 = Car.new # Output: 1
car2 = Car.new # Output: 2
v3 = Vehicle.new # Output: 4
Let's review the example above. A class instance variable called #count is set in the Vehicle class, with an initial value of 0. Every time the Vehicle class is instantiated, the initialize method calls self.increment_count to increment the value of #count and self.show_count to return the new value. Then, we have the Car class, which is a subclass of Vehicle and inherits all of its methods. However, it does not inherit the #count class instance variable, as this type of variable is not inheritable. That's why the counter works within the Car class, but it has its own count.
Methods prefixed with self., such as self.increment_count and self.show_count, are class methods. That is the only kind of method capable of accessing class instance variables.
That's just not how the language is built. Maybe look at openstruct
require 'ostruct'
obj = OpenStruct.new(my_var: 1)
obj.my_var
# => 1
By the way, you're method of setting up an instance variable is not correct. You should only be setting instance variables inside instance methods or initialize, otherwise use class variables or constants.
An example with constants:
class Foo
MyVar = 1
end
Foo::MyVar
# => 1
You could also make Foo.new.#my_var work with method_missing:
class Foo
def method_missing(m, *args, &block)
self.instance_variable_get(m)
end
def initialize
#my_var = 1
end
end
Foo.new.#my_var
# => 1

How should I define an instance variable in Ruby whose processing algorithm is defined in a super class?

In short: I want to define the algorithm in the superclass which inherits into all subclasses, but I want to define the data (on which the algorithm operates) in the subclasses as instance variables, which come into being when I call the "new" method of the given classes. What is the standard way for doing this in Ruby?
My solution is (but I am not exactly sure this is the right way):
class A
attr_accessor :var
def initialize
#var=nil #I dont know the actual value, it will be defined only in the more specific subclasses.
end
def process_data
puts #var #simply puts it out
end
end
#in my program all further classes are inherited form class A, the processing facility is inherited, only the data varies.
class B < A
attr_accessor :var
def initialize
#var=10 #specific value for class B which is always 10, no need for example b=B.new(20)
end
end
class C < A
attr_accessor :var
def initialize
#var=20 #specific value for class C which is always 20, no need for example c=C.new(20)
end
end
b=B.new
b.process_data #needs to print 10
c=C.new
c.process_data #needs to print 20
What you have works. There's just some unneeded stuff in there:
Instance variables evaluate to nil if they are uninitialized and they spring into existence as soon as they are used, so your A#initialize method is unnecessary.
You override the A#var and A#var= methods in B and C with methods that do the exact same thing. There is no need for that, just get rid of the calls to attr_accessor in the definition of B and C.
You create var and var= accessor methods but you never use them. Either get rid of the call to attr_accessor or (preferably) use the accessor methods, i.e. use self.var = in initialize and puts var in process_data.
class A
attr_accessor :var
def process_data
puts var #simply puts it out
end
end
#in my program all further classes are inherited form class A, the processing facility is inherited, only the data varies.
class B < A
def initialize
self.var = 10 #specific value for class B which is always 10, no need for example b=B.new(20)
end
end
class C < A
def initialize
self.var = 20 #specific value for class C which is always 20, no need for example c=C.new(20)
end
end
b = B.new
b.process_data #needs to print 10
c = C.new
c.process_data #needs to print 20
[Note: your coding style was also off. Indentation is 2 spaces in Ruby, not 3.]
However, if the value of #var is always the same for all instances of B, then why do you need multiple instances of B?
Why not something like this:
class A
attr_accessor :var
def initialize(val)
self.var = val
end
def process_data
puts var #simply puts it out
end
end
b = A.new(10)
b.process_data #needs to print 10
c = A.new(20)
c.process_data #needs to print 20
You are doing it in almost the right way. A minor point is that your A::initialize definition is redundant for two reasons:
An instance variable is initialized to nil automatically.
The initialize methods in the subclasses will override A::initialize when the subclass instances are created.
Also, the attr_accessor calls in the subclasses are redundant.
Now I seem to get what you wanted. You can use class-level instance variables.
class A
def initialize
#var=self.class.instance_variable_get(:#var)
end
def process_data
puts #var
end
end
class B < A
#var = 10
end
class C < A
#var = 20
end
B.new.process_data # => 10
C.new.process_data # => 20

Ruby and class variables in inherit class

class A
def set(v)
##v = v
end
def put
puts ##v
end
end
class B < A
end
class C < A
end
B.new.set 'b'
B.new.put # => b
C.new.set 'c'
C.new.put # => c
B.new.put # => c
Why? And how should I write this to have 'b' in last B.new.put?
Here is a nice article on the subject - Class and Instance Variables In Ruby.
Basically, what you can do is:
class A
class << self
attr_accessor :class_var
end
def set_class_var(value)
self.class.class_var = value
end
def get_class_var
self.class.class_var
end
end
class B < A; end
A.class_var = 'a'
B.class_var = 'b'
puts A.class_var # => a
puts B.class_var # => b
A.new.set_class_var 'aa'
B.new.set_class_var 'bb'
puts A.new.get_class_var # => aa
puts B.new.get_class_var # => bb
To understand it you should think about A as an instance of Class class (and that's how it is in Ruby). But every object in Ruby has its own singleton class that stores object-specific stuff like methods defined on object itself:
a = A.new
def a.foo
puts 'foo'
end
In that case foo is method defined only for a object and not for every instance of A class. And another way to define method in object's singleton class is like that:
class << a # open a's singleton class
def bar # define method that will be available only on 'a' object
puts 'bar'
end
end
In the first code snippet we use that approach to define class_var attribute accessor in the context of singleton class of our A class (it's a bit tricky, so you need to think about it). As the result class itself has class_var variable as well as its descendant class B. The difference is that every one of them has its own class_var variable that do not interfere.
Another option is to pull out class_inheritable_accessor code from Rails and include its behavior in your classes. See here for a good discussion and the guts of the code.
Perhaps you don't really want a class variable, though.
Assigning a value to a class variable (an ## variable) sets it for EVERY instance of the class. It even "sets" it for instances that "aren't created yet." So, consider this...
B.new.set 'b' # OK, that set ##v for that particular instance of B
B.new.put # Hey, you just created *another* new instance of B!
How can ##v have a value in that one? The second object's value of ##v would be unset, except for the fact that ##v is a class variable, so it has the same value for every instance of the class.

Resources