5

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

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • 1
    What do you want `.getX` to return in this case? You are overriding the field after calling super, so the output should really be the one you're getting. – Dogbert Mar 18 '11 at 13:58
  • @Dogbert: look at [this example in Java](http://ideone.com/yNLKT). "from Sup" is the correct answer – Claudiu Mar 18 '11 at 14:03
  • if use privateField instead of @privateField you will get "from sup" as a result. – krunal shah Mar 18 '11 at 14:06
  • @krunal shah: doesn't seem to work.. can you post an answer and be more explicit? – Claudiu Mar 18 '11 at 14:09
  • 1
    You can also translate this to Python, using __privateField. Python renames __privateField to __Sub_privateField and __Sup_privateField in each class. I'm not sure if there is an analogue in Ruby. – Arjun Guha Mar 18 '11 at 14:13

4 Answers4

9

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.

hoha
  • 4,418
  • 17
  • 15
1

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.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
  • hmm is kind of avoiding the issue. this is a contrived example, so contriving it a different way doesnt help to answer it =P. – Claudiu Mar 18 '11 at 14:21
1

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

RameshVel
  • 64,778
  • 30
  • 169
  • 213
-1

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 }
BurmajaM
  • 724
  • 5
  • 10