开发者

Ruby - how to handle problem of subclass accidentally overriding superclass's private fields?

开发者 https://www.devze.com 2023-02-18 18:53 出处:网络
Suppose you write a class Sup and I decide to extend it to Sub < Sup. Not only do I need to understand your published interface, but I also need to understand your private fields. Witness this fail

Suppose you write a class Sup and I decide to extend it to Sub < Sup. Not only do I need to understand your published interface, but I also need to understand your private fields. Witness this failure:

class Sup

  def initialize
    @privateField = "from sup"
  end

  def getX
    return @privateField
  end
end

class Sub < Sup

  def initialize
    super()
    @privateField = "i really hope Sup does not use this field"
  end
end

obj = Sub.new
print obj.getX #  prints "i really hope Sup does not use this field"

The question is, what is the right way to tackle this problem? It s开发者_如何转开发eems a subclass should be able to use whatever fields it wants without messing up the superclass.

EDIT: The equivalent example in Java returns "from Sup", which is the answer this should produce as well.


Instance variables have nothing to do with inheritance, they are created on first usage, not by some defining mechanism, therefore there is no special access control for them in language and they can not be shadowed.

Not only do I need to understand your published interface, but I also need to understand your private fields.

Actually this is an "official" position. Excerpt from "The Ruby Programming Language" book (where Matz is one of the authors):

... 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.

If you don't know it inside and out you're on your own. Sad but true.


Don't subclass it!

Use composition instead of inheritance.

Edit: Rather than MyObject subclassing ExistingObject, see if my_object having an instance variable referring to existing_object would be more appropriate.

Instance variables belong to instances (ie objects). They're not determined by the classes themselves.


unlike java/C#, in ruby private variables are always visible to the inheriting classes. There is no way to hide the private variables.


Ruby and Java don't treat 'private' property the same way. In Ruby if you mark something as private it only means that it can't be called with receiver, i.e.:

 class Sub
   private
   def foo; end
 end

sub.foo => error accessing private method with caller

but you can always access it if you change who is self like:

sub.instance_eval { foo } #instance_eval changes self to receiver, 'sub' in this example

Conclusion: Don't rely that you can hide or protect something from outer space! Or with great power comes great responsibility!

EDIT:

Yes, I know question was for fields but it's the same thing. You can always do:

sub.instance_eval { @my_private_field = 'something else' }
puts sub.instance_eval { @my_private_field }
0

精彩评论

暂无评论...
验证码 换一张
取 消