robert williams
robert williams

Reputation: 767

can instance variable be accessed by sub classes in ruby?

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

Answers (7)

J&#246;rg W Mittag
J&#246;rg W Mittag

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

Sagar Pandya
Sagar Pandya

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

tadman
tadman

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

Arie Xiao
Arie Xiao

Reputation: 14082

A Ruby instance consists of

  1. a collection of instance variables (data)
  2. a reference to the type which defines the behavior

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

Taryn East
Taryn East

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

Amadan
Amadan

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

sreeraj nyros
sreeraj nyros

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

Related Questions