How to make attributes in Ruby private/inaccessible?

Hi,

class Base	
	def initialize
		@test = 123
	end
end

class Child < Base
	def output
		print @test
	end
	
	public :output
end


child = Child.new
child.output

Prints out 123.

If attribute “test” is private, why I am able to access it in Child class?
If attribute “test” is not private, what the hell am I missing?
How do I make it really private?

I really new to this Ruby stuff so please be polite.

Ruby has no private/public instance variable, they are all protected. You cannot access them from outside the class, but not because you have to access, but because there is no access. Everything goed through methods that return the values of instance variables and set them. So you can’t make instance variables private. Are you coming from C#? All methods are public by default so you don’t have to:

public :output

Most people use:

class Example
  def one #this one is public
    #code...
  end

  private
    def two #this is private
    end

    def three #private
    end

  protected
    def four #protected
    end

    def five #protected
    end

  public
    def six #public again
    end
end

So every method after protected is protected until the ruby interpreter hits another modifier.

Thanks for the reply.

No private attributes? All protected. Check. I don’t really know if this is a good thing in general, but I can’t think of any counterexample at the moment so maybe yes.

Ok but now look
(Copy&Paste from http://www.rubycentral.com/book/tut_classes.html)

Protected access is used when objects need to access the internal state of other objects of the same class. For example, we may want to allow the individual Account objects to compare their raw balances, but may want to hide those balances from the rest of the world (perhaps because we present them in a different form).

class Account
  attr_reader :balance       # accessor method 'balance'


  protected :balance         # and make it protected


  def greaterBalanceThan(other)
    return @balance > other.balance
  end
end

Because the attribute balance is protected, it's available only within Account objects.

If what you say is true, it means that this code (attr_reader, protected mumbo jumbo) is simply not necessary because I can (as I demonstrated before) access the attribute directly.

I think this example in docs is really missleading.

No I’m not comming from C#. I am programming mostly in PHP and Java. Thank god no J2EE :wink:

You’ve got to remember that that doesn’t create @balance, rather it is more a shortcut for this:

class Account
  def balance
    @balance
  end
end

So when you do protected :balance it is exactly the same thing which happens when you do protected :some_other_method.

Though this mightbe useful:

class Account
  def balance
    @balance / 8
  end

  def balance= (val)
    @balance = val * 8
  end

  protected :balance, :balance=         # and make it protected


  def greaterBalanceThan(other)
    return balance > other.balance # uses self.balance instead of @blanace
  end
end

Douglas

DOUGBTX: Yes, yes, I know it now. I am pointing finger at the online book.

Imagine me (a Ruby wanna-learn with some OO experience) reading this

The Song objects we’ve created so far have an internal state (such as the song title and artist). That state is private to those objects—no other object can access an object’s instance variables. In general, this is a Good Thing. It means that the object is solely responsible for maintaining its own consistency.

Then comes the example how to make these “private” attributes protected.

Then I try to access them directly (by mistake) and WOW it works!

Really misleading examples. Why on earth is there not written that attributes are protected by default. One sentence. Or maybe I am stupid and just can’t find it.

Hmm, yes, there is some fuzzyness there. I have to say, it totally passed me by, I read that book ages ago, and whenever I see @foo, I think “private”, but when I think “private” I’m really thinking “protected” - I’ve never really seen the point of private. And besides, bar.instance_variables :slight_smile:

Douglas

Well, it might be so natural for Ruby programmers that all attibutes act like this, and besides, attributes are not exactly “protected”. There is just no way of accessing them from the outside. It is a different scope. You can only send messages (call methods) to objects.

Well no instance of another object can access those variables. But a a subclass sure can. So yes, the variables are only protected but, the wording there isn’t incorrect.


>> class MyPrivates
>>   def initialize
>>     @google = 'search'
>>     @apple = 'it'
>>   end
>> end

>> my = MyPrivates.new
=> #<MyPrivates:0x2cfa470 @apple="it", @google="search">
>> my.instance_variable_get(:@apple)
=> "it"
>> my.instance_variable_get(:@google)
=> "search"

>> my.instance_variables.each { |name| puts "#{name} => #{my.instance_variable_g
et(name)}" }
@apple => it
@google => search

Interesting choice of class name :wink:

Off Topic:

Excuse me but… HAHAHAHAHHAHA didn’t notice until you said so :slight_smile: Oh well I should grow up. hehe… hehehehe.

Nothing wrong with a bit of childish humor from time to time…:wink:

Anyway, if you really wanted to make your instance variables private, could you not just do:


class YourPrivates
  private :instance_variables
end

No, because attributes are can be accessed directly from subclass. You don’t have to make any setters/getters.

I meant from outside of the class. See the example above on how to access instance variables from outside of the class. By making the instance_variables() method private, you should disable access to them that way.

There isn’t a way to make things entirely private or protected in ruby right now. No matter what you do to try to protect something, you can always use send or send to access private or protected vars or methods.

Check these commands for more info:

$ ri send
OR
$ ri send

Cheers-
-Ezra

Here’s a quote I just came across:

I started programming by learning C++. I got up to the part about public, private, protected, friend, etc… got very annoyed by the unnecessary bureaucracy of it all and dropped the language… If I can’t trust the programmers around me not to muck around in my guts without good reason, I can’t trust them at all. And if they’re willing to perform that bad practice, they’ll probably do more anyway. It’s not worth worrying about.

source

It’s a bit of a moot point, considering we have open classes.

>> class Foo
>>   def initialize
>>     @foo = "bar"
>>   end
>> end
=> nil
>> f = Foo.new
=> #<Foo:0x2cfbfb8 @foo="bar">
>> def f.foo
>>   @foo
>> end
=> nil
>> f.foo
=> "bar"

Oh, and good to know somone actually reads the code I post :slight_smile:

Douglas

DOUG: There is absolutely some really rational thinking in that citation. I’ve never thought of access control this way. On the other hand, I think in some cases it can be better if you declare some variables as protected (or whatever that means in ruby). Encapsulation is a good thing in general. You don’t need to know the internals of classes if you are using it. It would be only missleading. We all dream about nice APIs. So why polute them with unneccessary ‘internal’ attributes?

That’s what I’m thinking.

And if you take “protected” to mean “you’ve got to put in noticeable effort when you are outside,” and “public” to mean “always easy to get at,” then I think that covers it.

Douglas