From the examples in this FAQ, it seems like protected works a bit more like Java's private - you can use it only inside the class, but for any object of that class, not just self, right? (with the exception that it applies to subclasses)
So Ruby's private only allows you to interact with other methods on the current object. Protected allows objects of the same class to send each other the message, but not other classes. Would this be a fair summary?
Ruby private literally does nothing. It's a marker with some side effects, but isn't actually protecting anything. You can trivially do obj.send(:private_method) for any method, private or not.
It's been about a year since I last looked at Ruby code (a true fave, holds it down, easy to love), but I'm pretty sure that's the idea.
In Ruby, the private keyword is more about controlling the visibility of methods rather than providing strict access control. It's a part of Ruby's philosophy of "convention over enforcement." While it does mark methods as private, it doesn't prevent you from calling them using .send. This is a design choice in Ruby to prioritize flexibility and programmer discretion.
Here's a bit more detail on how it works:
Method Visibility: When you declare a method as private, you're essentially saying that it should only be used within the class where it's defined (or its subclasses). This is a way to indicate the intended usage of a method.
No Strict Access Control: Unlike some other languages, Ruby doesn't enforce strict access control. It trusts the developer to follow conventions. However, this doesn't mean you should casually break encapsulation. It's a matter of design and discipline.
send and public_send: The send method allows you to invoke any method, including private ones, on an object. It's a powerful feature that can be handy in some situations but should be used with caution. There's also public_send, which respects the visibility rules and won't invoke private methods.
Here's an example:
class MyClass
def public_method
puts "This is a public method"
end
private
def private_method
puts "This is a private method"
end
end
obj = MyClass.new
obj.public_method # works, prints the string
obj.private_method # fails, no method
irb(main):014:0> obj = MyClass.new
=> #<MyClass:0x00000001368fd6d0>
irb(main):015:0> obj.public_method
This is a public method
=> nil
irb(main):016:0> obj.private_method
Traceback (most recent call last):
4: from /usr/bin/irb:23:in `<main>'
3: from /usr/bin/irb:23:in `load'
2: from /Library/Ruby/Gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
1: from (irb):16
NoMethodError (private method `private_method' called for #<MyClass:0x00000001368fd6d0>)
Did you mean? private_methods
irb(main):017:0> obj.send(:private_method)
This is a private method
=> nil
irb(main):018:0>
To be fair, you can also use reflection in Java to call private methods or access private fields, especially since they removed the security managers. Just because there are ways around it doesn't mean "it does nothing".
https://www.ruby-lang.org/en/documentation/faq/7/
(On this page there’s a section called “What’s the difference between private and protected?” which explains it.)
It’s interesting in its own right, and it’s in my backlog to blog about because I don’t like any of the existing resources contrasting the two.