Reputation: 767
I recently started learning ruby . i would like to know what exactly is instance variable in ruby. i have written a small code to learn what instance variable is .
class Animal
def animal_sound
@sound = "roar"
@sound + " "+"animal"
end
end
class Human < Animal
def human_sound
@sound + " "+"human"
end
end
human = Human.new
p human.animal_sound
p human.human_sound
output:
"roar animal"
"roar human"
I know that instance variable belong only to one class and it's sub-classes are separate.But how did my human class was able to access @sound from animal class?
Upvotes: 2
Views: 78
Reputation: 369594
I know that instance variable belong only to one class
No. Instance variables belong to objects (aka instances). That's why they are called instance variables, after all.
But how did my human class was able to access @sound from animal class?
It wasn't. The instance variable belongs to human
.
Upvotes: 0
Reputation: 9508
Human class is effectively the same as:
class Human
def animal_sound
@sound = "roar"
@sound + " " + "animal"
end
def human_sound
@sound + " " + "human"
end
end
For your new instance human = Human.new
, when you call animal_sound
, this defines @sound
for your particular instance human
.
Because @sound
is an instance-variable it's available to all other methods available to human
. That is, @sound
can be seen in human_sound
as well.
Notice if you call human_sound
before animal_sound
, @sound
will return nil
which will result in an error. Since @sound
is to be used elsewhere it would be reasonable to define it in a special initialize
method. This way @sound
is automatically defined as specified for every new instance.
Now it doesn't matter in which order you call animal_sound
and human_sound
.
class Human
def initialize
@sound = "roar"
end
def animal_sound
@sound + " " + "animal"
end
def human_sound
@sound + " " + "human"
end
end
human = Human.new
human.human_sound #=> "roar human"
human.animal_sound #=> "roar animal"
Upvotes: 0
Reputation: 211720
Instance variables aren't "inherited" per-se, but since they live in the context of the instance itself they are accessible by any and all methods that instance has.
Think of an object as a container that has associated methods and instance variables. You can add, remove, and alter these as you see fit, though normally adding and removing methods is only done once in your class definition. It's just that since Ruby is highly dynamic, you can actually do this whenever you want.
For example, here's a rewritten demonstration:
class Animal
def initialize(name = nil)
# Define a local instance variable that defines their name
@name = name || 'Betsy'
end
def animal_sound
# Default noise an animal makes
'moo'
end
def sound
# A more personalized sound effect
'%s goes %s' % [ @name, animal_sound ]
end
end
class Human < Animal
def animal_sound
# Override the default behaviour based on name
case (@name)
when 'Bruce'
# Where anyone named Bruce does something different
'yo'
else
'rawr'
end
end
end
chucky = Human.new('Chucky')
p chucky.sound
# => "Chucky goes rawr"
bruce = Human.new('Bruce')
p bruce.sound
# => "Bruce goes yo"
Here @name
is assigned in the parent class initializer, but it's bound to the instance itself, which is actually of type Human
, so it's accessible to any methods like animal_sound
in Human. Note that this works in reverse, too, the parent class is calling animal_sound
but the one that ends up being used is the subclass version, not the parent's, because the subclass defined different behaviour.
This is the cornerstone of object oriented-programming.
Upvotes: 2
Reputation: 14082
A Ruby instance consists of
In your example, the instance human
can be interpreted as
...
|
Object { ... }
|
Animal { def animal_sound }
human -----> {@sound} |
<type> ----------------> Human { def human_sound }
Any instance methods (behavior) available on the human
instance will operate on the same set of instance variables in part 1. In your example, this is {@sound}
.
Upvotes: 2
Reputation: 27747
Your example code doesn't show good use of instance variables... it shows use of instance methods (and inheritance of them from the parent class). An instance variable is a variable that is accessible to just that instance.
Here's an example:
class Animal
def animal_sound
@sound = "roar"
@sound + " "+"animal"
end
# This reader-method lets us see the value of the @eye_colour instance-variable
def eye_colour
"My eyes are: #{@eye_colour}"
end
# This writer-method lets us set the value of the @eye_colour instance variable
def eye_colour=(new_colour)
@eye_colour = new_colour
end
end
class Human < Animal
def human_sound
@sound + " "+"human"
end
# inherits the colour-methods from Animal
end
# when you create a new instance of human, you can give them an eye-colour
human = Human.new
human.eye_colour = "Green"
human.eye_colour # => "My eyes are: Green"
# if you create a new instance of human, you can give them a different eye colour
human2 = Human.new
human2.eye_colour = "Brown"
human2.eye_colour # => "My eyes are: Brown"
# but the first human is still the original colour -
# because the variable contains a value just for *that* instance.
# This is what it means to be an instance-variable
human.eye_colour # => "My eyes are: Green"
Upvotes: 1
Reputation: 198476
how did my human class was able to access @sound from animal class?
It didn't. It accessed the method (Animal#animal_sound
), which is inherited. When you did human.animal_sound
, it attached @sound
to the current self
, i.e. human
-- the instance (not to Human
, and not to Animal
). @sound
does not belong to classes; it belongs to instances (which is why it's called an instance variable). Then, human.human_sound
read @sound
from the current self
again, i.e. human
(not from Human
, not from Animal
).
Upvotes: 3
Reputation: 979
The Human
class is inherited from the Animal
class. So the instance variable @sound
initiate in Animal
class is accessable in Human
class.
Like the sub class inheriting the properties from the parent class.
Upvotes: 0