Can Ruby subclass instance variables _overwrite_ t

2019-06-28 04:32发布

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> 

2条回答
forever°为你锁心
2楼-- · 2019-06-28 05:17

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.

查看更多
走好不送
3楼-- · 2019-06-28 05:22

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

查看更多
登录 后发表回答