Question

How to make instance variables private in Ruby?

Is there any way to make instance variables "private"(C++ or Java definition) in ruby? In other words I want following code to result in an error.

class Base
  def initialize()
    @x = 10
  end
end

class Derived < Base
  def x
    @x = 20
  end
end

d = Derived.new
 45  55228  45
1 Jan 1970

Solution

 40

Like most things in Ruby, instance variables aren't truly "private" and can be accessed by anyone with d.instance_variable_get :@x.

Unlike in Java/C++, though, instance variables in Ruby are always private. They are never part of the public API like methods are, since they can only be accessed with that verbose getter. So if there's any sanity in your API, you don't have to worry about someone abusing your instance variables, since they'll be using the methods instead. (Of course, if someone wants to go wild and access private methods or instance variables, there isn’t a way to stop them.)

The only concern is if someone accidentally overwrites an instance variable when they extend your class. That can be avoided by using unlikely names, perhaps calling it @base_x in your example.

2010-01-25

Solution

 32

Never use instance variables directly. Only ever use accessors. You can define the reader as public and the writer private by:

class Foo
  attr_reader :bar

  private

  attr_writer :bar
end

However, keep in mind that private and protected do not mean what you think they mean. Public methods can be called against any receiver: named, self, or implicit (x.baz, self.baz, or baz). Protected methods may only be called with a receiver of self or implicitly (self.baz, baz). Private methods may only be called with an implicit receiver (baz).

Long story short, you're approaching the problem from a non-Ruby point of view. Always use accessors instead of instance variables. Use public/protected/private to document your intent, and assume consumers of your API are responsible adults.

2012-01-24