Ruby class instance variable vs. class variable
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]
Difference between class variables and class instance variables?
A class variable (@@
) is shared among the class and all of its descendants. A class instance variable (@
) is not shared by the class's descendants.
Class variable (@@
)
Let's have a class Foo with a class variable @@i
, and accessors for reading and writing @@i
:
class Foo
@@i = 1
def self.i
@@i
end
def self.i=(value)
@@i = value
end
end
And a derived class:
class Bar < Foo
end
We see that Foo and Bar have the same value for @@i
:
p Foo.i # => 1
p Bar.i # => 1
And changing @@i
in one changes it in both:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
Class instance variable (@
)
Let's make a simple class with a class instance variable @i
and accessors for reading and writing @i
:
class Foo
@i = 1
def self.i
@i
end
def self.i=(value)
@i = value
end
end
And a derived class:
class Bar < Foo
end
We see that although Bar inherits the accessors for @i
, it does not inherit @i
itself:
p Foo.i # => 1
p Bar.i # => nil
We can set Bar's @i
without affecting Foo's @i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
Difference between Ruby's class variable and instance variable
I think "instance variable, class variable and the difference between them in ruby" has a good explanation of the difference between local, instance and class variables.
Normal Variables Vs Instance variable in Ruby, Whats the difference?
A normal variable has scope only within the current context; an instance variable has scope throughout one instance of a class. In your case they're confused because the context is main
, which acts as an instance of Object
.
Consider the following, which may make things clearer
class User
def set_name
@name = "Bob"
surname = "Cratchett"
end
def hi
puts "Hello, " + @name
end
def hello
puts "Hello, Mr " + surname
end
end
irb(main):022:0> u = User.new
=> #<User:0x29cbfb0>
irb(main):023:0> u.set_name
irb(main):024:0> u.hi
Hello, Bob
=> nil
irb(main):025:0> u.hello
NameError: undefined local variable or method `surname' for #<User:0x29cbfb0 @name="Bob">
difference between class method , instance method , instance variable , class variable?
First take a look at this diagram:
You can rightly say that “obj has a method called my_method( ),” meaning that you’re able to call obj.my_method(). By contrast, you shouldn’t say that “MyClass has a method named my_method().” That would be confusing, because it would imply that you’re able to call MyClass.my_method() as if it were a class method.
To remove the ambiguity, you should say that my_method() is an instance method (not just “a method”) of MyClass, meaning that it’s defined in MyClass, and you actually need an instance of MyClass to call it. It’s the same method, but when you talk about the class, you call it an instance method, and when you talk about the object, you simply call it a method. Remember this distinction, and you won’t get confused when writing introspective code like this:
String.instance_methods == "abc".methods # => true String.methods == "abc".methods # => false
an object’s instance variables live in the object itself, and an object’s methods live in the object’s class. That’s why objects of the same class share methods but don’t share instance variables.
Constants vs instance variable
Consider this class:
class Dog
NUMBER_OF_LEGS = 4
@dog_counter = 0
attr_reader :name
def initialize(name)
@name = name
end
def legs
NUMBER_OF_LEGS
end
end
Here, NUMBER_OF_LEGS
is a constant, @name
is an instance variable (with a getter method), and @dog_counter
is what's called a class instance variable.
In Ruby everything is an object, even classes, and as such they can have their own instance variables.
Look at how we could use this class:
dog = Dog.new('Chewbacca')
dog.name
# => 'Chewbacca'
dog.legs
# => 4
Dog::NUMBER_OF_LEGS
# => 4
That's fine, but we do not have a direct interface to access @dog_counter
. The only way to do something with it is to use introspection methods:
dog.class.instance_variable_get(:@dog_counter)
# => 0
dog.class.instance_variable_set(:@dog_counter, 1)
dog.class.instance_variable_get(:@dog_counter)
# => 1
dog.class.instance_eval { @dog_counter = 10 }
dog.class.instance_variable_get(:@dog_counter)
# => 10
We can do better than that. Look at this other implementation:
class Dog
@dog_counter = 0
attr_reader :name
class << self
attr_accessor :dog_counter
end
def initialize(name)
@name = name
self.class.dog_counter += 1
end
end
Now we have defined a class accessor (setter and getter), and we're also incrementing it with each new instance. The interface is simple:
Dog.dog_counter
# => 0
dog_1 = Dog.new('Han')
dog_2 = Dog.new('Luke')
Dog.dog_counter
# => 2
dog_2.class.dog_counter
# => 2
As to proper class variables, they are scoped on the class and can be accessed by instances.
The big problem, however, is that they are shared between all classes in the same hierarchy. Each class that sets a new value will update it for all its ancestors and descendants.
For this reason they are generally avoided, and class instance variables are preferred (they are class specific).
class Scientist
@@greet = "Hello, I'm a Scientist!"
def greet
@@greet
end
end
class Biologist < Scientist
@@greet = "Hello, I'm a Biologist!"
end
class Physicist < Scientist
@@greet = "Hello, I'm a Physicist!"
end
class ParticlePhysicist < Physicist
@@greet = "Hello, I'm a ParticlePhysicist!"
end
biologist = Biologist.new
biologist.greet
# => "Hello, I'm a ParticlePhysicist!"
Related Topics
In Ruby, How Does Coerce() Actually Work
How to Call a Controller'S Method from a View (As We Call from Helper Ideally)
Can You Ask Ruby to Treat Warnings as Errors
What Does Class_Eval ≪≪-"End_Eval", _File_, _Line_ Mean in Ruby
Execute Bash Commands from a Rakefile
Ruby Local Variable Is Undefined
How to Monitor Delayed_Job With Monit
Are Crlf Lines Ok in a Rails Project Deployed on Linux
Ruby: Parsing a String Representation of Nested Arrays into an Array
Turning Long Fixed Number to Array Ruby
Converting an Integer to a Hexadecimal String in Ruby
Is There a Better Way of Checking Nil or Length == 0 of a String in Ruby