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