1

In these two posts:

  1. Instance Variables Inheritance

  2. Can Ruby subclass instance variables _overwrite_ the superclass's (same name)?

People were writing about how in all OOP languages the superclass and derived classes don't have separate objects, and that when you create an instance of the derived class, it is also an instance of the superclass. There is one object and it's both classes at once.

Well, the problem is I don't get it? How can an object be both classes at once? And how can there instance variables be the same, if they use the same name of course?

I mean I get that subclasses get methods from there superclasses, but I don't get how they share there instance variables?

I've looked through at least four Ruby books and all that I've found was that instance variables don't get shared through the inheritance chain?

Could somebody please give a brief explanation of how and why the "instance variables" from the subclass are actually stored in the super class?

2
  • Even though the question ends with asking for book recommendation, the thing being asked is narrow enough to be answered in SO format. Commented Jan 6, 2016 at 15:58
  • Just edited, hopefully it now complies, as it is a good question IMHO Commented Jan 6, 2016 at 16:32

2 Answers 2

3

The key thing to understand here is: instance variables are associated with the current object (or instance), while methods are associated with classes.

The reason for that is you don't want to have new methods created for every single object created if they are going to have the same body as all the other objects of that class.

On the other hand, instance variables have to be individual for each object, otherwise you will have a complete mash up when mutating values.


With that in mind, lets consider the following example:

class Foo
  def foo
    @var = :foo
  end
end

class Bar < Foo
  def bar
    @var = :bar
  end
end

Lets explore what happens when we create a new object:

baz = Bar.new

Currently, baz doesn't have any instance variables. It just has a pointer that says "Bar is my class".

baz.class # => Bar

The Foo or Baz classes don't have any such thing as @var associated with them. So currently, no one knows about @var.


When you call a method on baz, the method definition is searched in the Bar ancestors chain:

baz.class.ancestors # => [Bar, Foo, Object, Kernel, BasicObject]

You can note a few things here: Firstly, the things there appear in the order of inheritance. Secondly, Foo implicitly inherits from Object. Thirdly, modules can also be part of the chain (like Kernel).

baz.bar # => :bar

Will find the first thing in the chain that has a method #bar and call that. The value is assigned to the @var instance variable, which is associated with the object baz, not the classes Foo or Bar.

baz.foo # => :foo

Will now use the method definition from Foo. But again, @var is being changed in baz.


A few related things for future reading (as some of the above is not completely accurate for simplicity's sake):

  • singleton classes
  • class variables
  • including/prepending modules
  • Class.superclass # => Module
  • BasicObject#method_missing
Sign up to request clarification or add additional context in comments.

2 Comments

but If a subclass uses an instance variable with the same name as an instance used by one of its ancestors, will it not overwrite the value of its ancestor’s variable?
@user3867776, it will overwrite it. That is because it doesn't matter which class in the chain changes the value. The value is not in any way associated with any of the classes. There is only one @var - part of the baz object.
1

Instead of classes lets think about real things.

say you have the concept of a Pet, and lets say that all have pets have a name. Now lets say you have the the concept of PetDog, which like all pets has a name, but also has a "breed".

As you can see its perfectly reasonable to think of a PetDog, as both a Pet (its superclass) and as a PetDog (a subclass of Pets)

More mathematically you can think of a class a set of all objects with some similar characteristic, and then the subclass "surrounds" the superclass and has even more characteristics.

class Food
  attr_accessor :name
end

class Fruit < Food
  attr_accessor :ripeness
end

banana = Fruit.new
banana.ripeness = 0 # very green banana
banana.name = "banana"  

steak = Food.new
steak.ripeness = 3 # ERROR... the base class Food does not know about "ripeness"

How about a real (working) example? Lets use the react.rb DSL to define a Clock and Alarm UI components

The Clock component class is subclass of React::Component::Base so gets a lot "state" that is part of the base class. It knows how to render to html, it knows how to react when things update, etc. This all part of the base class, and all the data to control that and make it work stays in the base class.

In addition Clock ihas some special properties, i.e. it keeps track of the current time in the @clock variable. It also updates itself every second.

Then we make a subclass of that, called Alarm.

Because an Alarm is a subclass of Clock it has that internal @clock variable (which is actually part of the clock class), and like any other Clock, Alarms update themselves every second. This is important! Notice that it is the Clock class that initializes the @clock variable, and it is also the Clock class that uses the clock to update (redisplay) itself. When Alarm inherits from Clock, the @clock variable must stay part of clock so that it behaves properly.

But in addition Alarm uses the @clock variable for its own purpose namely to check and see if "times up", and when it is up, it nicely stops the clock from running (notice that even after the alert is displayed, the Clock keeps running but the Alarm does not.

Hope this helps - make sure to run the example!

<div id="container"></div>
<script type="text/ruby">
class Clock < React::Component::Base
  # a component that displays the time
  after_mount do 
    @clock = every(1) { force_update! }
  end
  def render
    "#{Time.now}"
  end
end

class Alarm < Clock
  # a kind of clock that notifies its caller when time is up!
  param :at, type: Time
  param :notify, type: Proc
  before_update do  
    # before_update is a feature of React::Component::Base
    # the following code is executed before each update of the Alarm
    if Time.now > params.at
      params.notify
      @clock.stop
    end
  end
  def render
    "Alarm will go off in #{(params.at-Time.now).to_i} seconds"
  end
end

Element['#container'].render do
  div do
    # This is react.rb's way of creating a new instance of Clock
    # Its shorthand for doing a Clock.new() and a bunch of other stuff
    Clock()  
    br
    Alarm(
     at: Time.now+10.seconds, 
     notify: -> { alert ('beep beep beep') }
    )
  end
end

</script>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.