Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

In the Chapter 7.3.5 "Inheritance and Instance Variables" of the book "the ruby programing language" says :

Because instance variables have nothing to do with inheritance, it follows that an instance variable used by a subclass cannot “shadow” an instance variable in the superclass. If a subclass uses an instance variable with the same name as a variable used by one of its ancestors, it will overwrite the value of its >ancestor’s variable. This can be done intentionally, to alter the behavior of the ancestor, or it can be done inadvertently. In the latter case, it is almost certain to cause bugs. As with the inheritance of private methods described earlier, this is another reason why it is only safe to extend Ruby classes when you are familiar with (and in control of) the implementation of the superclass.

I had made my own test , but seems instance variables from subclass does NOT affect the superclass

my Ruby version

bob@bob-ruby:~$ ruby --version
ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux]
bob@bob-ruby:~$ 

Below is the code

class Point
   attr_accessor :x,:y
   def initialize(x,y)
     @x,@y=x,y
   end
end

class Point3D < Point
   attr_accessor :x,:y,:z
   def initialize(x,y,z)
     @x=x
     @y=y
     @z=z
   end
end

irb(main):052:0> p=Point.new(1,2)
=> #<Point:0x87e8968 @x=1, @y=2>
irb(main):053:0> q=Point3D.new(4,5,6)
=> #<Point3D:0x87e423c @x=4, @y=5, @z=6>
irb(main):054:0> q.x
=> 4
irb(main):055:0> p.x
=> 1
irb(main):056:0> 
like image 396
ailms Avatar asked Jan 26 '13 13:01

ailms


People also ask

Can we have a variable in a subclass with a same name as in the superclass?

If your subclass defines a member variable with the same name as a member variable in its superclass, the variable in the subclass hides the one in the superclass. Thus, the subclass does not inherit the variable from its superclass.

Does a subclass inherit instance variables?

Subclasses do not have access to the private instance variables in a superclass that they extend. Constructors are not inherited.

Can a Ruby module have instance variables?

Explanation: Yes, Module instance variables are present in the class when you would include them inside the class.

Are instance variables inherited in Ruby?

Instance variables are not inherited. If a method is written in the subclass with the same name and parameters as one in the parent class, the super class' method is overwritten.

What are instance and class variables in Ruby?

It is well known that Ruby has instance and class variables, just like any Object-Oriented language. They are both widely used, and you can recognize them by the @a and @@a notation respectively.

What is a derived class or sub-class in Ruby?

This existing class is called the base class or superclass, and the new class is called the derived class or sub-class . Let's learn to do all these things in Ruby. Let's start understanding this code by knowing the use of < first. < is used to make a sub-class.

What are class instance variables?

Here we shall introduce a bit of a weird concept: class instance variables. Basically you can recognize them because they look like instance variables, but you'll find them on a class level. They work like a regular class variable, but they differ with those because they are not shared with subclasses.

How to call the constructor of a super class from another superclass?

super will call the constructor of the superclass and will initialize it. So, super (name) will call the constructor of the superclass ( Child ) and will pass 'name' to it and that's it. Rest of the code is simple.


2 Answers

The book (emphasis and addition mine):

If a subclass uses an instance variable with the same name as a[n instance] variable used by one of its ancestors, it will overwrite the value of its ancestor’s variable.

I know you don't have two instances of the same class; we're specifically discussing inheritance.

When a subclass uses an instance variable with the same name as an instance variable used by the superclass, there's a single instance variable. If the subclass changes the value of that instance variable, and the superclass accesses it, it gets the value set by the subclass.

When a subclass is instantiated, it acts "as-if" it's also an instance of the superclass. The way Ruby is implemented means that if the superclass has an instance variable @foo, the subclass can access it. This makes a distinction between the subclass's @foo and the superclass's @foo meaningless.

This is how subclasses may alter superclass behavior: by setting a value the superclass might use. If a subclass sets @foo = 42, and a superclass method accesses @foo, it sees 42. This may or may not be intended, hence the warning. It can lead to spectacularly frustrating debugging sessions.

class MyStack
  def initialize
    @my_array = []
  end

  def push(item)
    @my_array << item
  end
end

# Stack class that keeps a list 
# of every item ever pushed.
class TrackingStack < MyStack
  def initialize
    super
    @my_array = []
  end

  def push(item)
    super
    @my_array << item
  end

  def all_items_ever_pushed
    @my_array
  end
end

TrackingStack introduces a bug, because it inadvertently used the same name as the superclass's array used to hold the stack contents. If you weren't familiar with the superclass's implementation, this would cause confusion and bugs until you dug deeply enough to understand where the unintended behavior came from.

An instance of the superclass is just that: an instance of the superclass, and it's meaningless to talk about how an instance of the subclass will affect it, because they're completely unrelated.

Here's a rephrasing:

Subclassing can be risky when you don't control, or are unfamiliar with, the superclass implementation. One reason is because the introduction of an instance variable in the subclass may overwrite the value of a superclass instance variable, leading to unintended behavior.

like image 90
Dave Newton Avatar answered Sep 27 '22 19:09

Dave Newton


Instance variables belong to instances, not to classes. The whole idea of "inheritance" doesn't even make sense there, inheritance only applies to classes.

like image 34
Jörg W Mittag Avatar answered Sep 27 '22 21:09

Jörg W Mittag