How to make instance variables private in Ruby?

Viewed 49302

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

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.

Unlike methods having different levels of visibility, Ruby instance variables are always private (from outside of objects). However, inside objects instance variables are always accessible, either from parent, child class, or included modules.

Since there probably is no way to alter how Ruby access @x, I don't think you could have any control over it. Writing @x would just directly pick that instance variable, and since Ruby doesn't provide visibility control over variables, live with it I guess.

As @marcgg says, if you don't want derived classes to touch your instance variables, don't use it at all or find a clever way to hide it from seeing by derived classes.

If you want protection against accidental modification. I think attr_accessor can be a good fit.

class Data
 attr_accessor :id
 
 private :id
end

That will disable writing of id but would be readable. You can however use public attr_reader and private attr_writer syntax as well. Like so:

class Data
 attr_reader :id
 
 private
 
 attr_writer :id
end
Related