For anyone learning Object Oriented Programming or Ruby or both, you know that there is a lot to learn. I’m still learning new things everyday. One of the topics that bothered me, and still bothers me, is the difference between public, private and protected instance methods.
As an attempt to better understand them, I’ve done some research on the topic and am writing down what I’ve learned. Hopefully this article will not only clear up the matter in my own head but help anyone else who is confused as well.
A basic understanding of Object Oriented Programming will be needed to understand this article. If you are unfamiliar with OOP, I suggest reading up on it first.
First Things First
What are public, private, and protected instance methods? Why do we use them? When do we use them?
To make it simple: public, private and protected methods are just that. Methods. You use them to perform certain functions on your code. The difference between the three comes from who and/or what has access to them.
Why do we use them? To provide a easy and simple interface for our classes. They allow us to write clean code and provide a enjoyable experience for the consumers of that code while protecting any sensitive data at the same time.
As for when do we use each one, that will require us to go more in-depth.
Public
Public methods are the generally considered the easiest to understand out of the three.
What are they?
Public methods are methods that are accessible both inside and outside the scope of your class. Any instance of that class will have access to public methods and can invoke them.
How do you use them?
You use them as you would any other method in ruby. Using dot notation, you can invoke a public method on a caller.
Let’s see it in action:
class Person
def initialize(name, age)
@name = name
@age = age
end
public
def name
@name
end
def age
@age
end
end
joe = Person.new('Joe', 30)
joe.name # => 'Joe'
joe.age # => 30
You can see above that joe is an instance of class Person. Since name and age are public instance methods, the joe object can access them even outside the scope of class Person.
As a side-note: you don’t need to preface public instance methods with public like I did in the code snippet above. All instance methods are public by default. I just did that to make it more clear.
When do you use them?
You certainly want to use public methods when displaying information for everyone to see.
A public method in human form.
You should also keep a method public if it is a part of that class’s interface. Meaning that other classes interact with that class via that method. Since that last sentence made no sense, here’s an example:
class Dog
attr_reader :name
def initialize(name)
@name = name
end
def speak
'Arf!'
end
end
class Owner
attr_reader :name, :pet
def initialize(name, pet_name)
@name = name
@pet = Dog.new(pet_name)
end
def call_pet
puts "#{name}: Hey #{pet.name}! Come here boy!"
puts "#{pet.name}: #{pet.speak}"
end
end
tom = Owner.new('Tom', 'Rufus')
tom.call_pet
# => "Tom: Hey Rufus! Come here boy!"
# => "Rufus: Arf!"
The above example is a bit long, but you can see that the speak method in the Dog class is part of its interface. The Owner class uses that method in it’s call_pet method to allow the pet to speak. Also, we could use *speak *method by itself if we want the dog object to speak on it’s own. Therefore we should keep it a public method
It’s also important to keep your method public when you want the program/client to be able to change the state of your object. For instance, say you have a car object and you want to spray paint it a different color:
class Car
def initialize(color)
@color = color
end
def spray_paint(new_color)
@color = new_color
end
def color
@color
end
end
my_car = Car.new('pink')
my_car.color # => 'pink'
my_car.spray_paint('black')
my_car.color # => 'black'
Private
Private methods are probably the next easiest to understand as protected are a bit more nuanced.
What are they?
Private methods are not accessible outside the scope of the class whatsoever. If you try to invoke a private method with a class object, an error will occur.
class TopSecret
private
def data
"Top secret information"
end
end
secret_file = TopSecret.new
secret_file.data
# => NoMethodError: private method `data' called for #<TopSecret:0x007f8051041ab8>
```
### How do you use them?
You may have also noticed that in order to make a method private, you have to preface it with the keyword *private. *Any methods that you create underneath *private* will be considered private methods and off limits.
(*private* is actually a ruby method itself, but it may be easier to think of it as a keyword/section divider)
Furthermore, private methods do not use dot notation and can only be called implicitly. This means that you will never reference **self**, or any other class instance, on a private method.
If you want to use a private method within the proper scope, just call it by its method name. Simple as that.
```ruby
class Mathy
def output_result(num1, num2)
puts crazy_algorithm(num1, num2)
end
private
def crazy_algorithm(num1, num2)
value = num1 * num2
value *= (num1 + num2)
value /= num1
value -= num2 / num1
value**2
end
end
equation = Mathy.new
equation.output_result(3, 5) # => 1521
```
### When do you use them?
Private methods are very useful when it comes to managing the interface of both your class and your program. They should be used when dealing with:
* Sensitive information, such as passwords, personal information, etc.
* Methods that serve as the inner workings of your class and don’t output or display information.
* Methods that don’t add to the interface and do not collaborate with other classes.
If you’re a developer building a video game app, you wouldn’t want the player to have access to the game settings, computer AI, or any other of the inner functions.
![What happens when you don’t use private methods](https://cdn-images-1.medium.com/max/2000/1*HmYW8e8Z1YoKHT7AGsk8wA.gif)*What happens when you don’t use private methods*
What about when you want certain people to access the information, but not everyone? That’s when you can use a public method to act as a go-between. This allows you to create a filter that only lets some people through. A password is a good example.
```ruby
class TopSecret
def access_data
puts "Please enter password:"
password_attempt = gets.chomp
if password_attempt == '12345'
puts data
else
puts 'Nice try, bozo.'
end
end
private
def data
"Top secret information"
end
end
secret_file = TopSecret.new
secret_file.access_data
```
In the above example, the *data* method is private so neither the client nor the program has access to it. But a secret is only fun if some people have access to it and they can shove it everyone else’s face, so I created a accessor method called *access_data*.
The *access_data* method requires a password from the user before it gives up its secrets. A wrong password attempt leaves them being called a bozo.
![](https://cdn-images-1.medium.com/max/2000/1*zzp3G8tT6cDL9HHZnjdW7w.gif)
## Protected
We now come to the protected instance methods, the odd one of the group.
### What are they?
Protected methods are a balance between public and private methods. They are similar to private methods in that they cannot be accessed in the public scope. Neither the client nor the program can invoke them.
```ruby
class Person
def initialize
@age = rand(50)
end
protected
def age
@age
end
end
me = Person.new
me.age # => NoMethodError: protected method `age' called
However, objects of the same class can access each other’s protected methods.
class Person
def initialize
@age = rand(50)
end
def >(other_person)
age > other_person.age
end
protected
def age
@age
end
end
me = Person.new
you = Person.new
me > you # => true
The ages are generated at random so the result of the above code won’t always be “true.” However, it will never produce an error, which is the most important take away.
Since you *and *me are objects of the same class — Person — they can access each other’s protected methods without issue.
How do you use them?
If you want to make a method protected, you must declare the protected *method first, similar to private methods. However, with protected methods, you *can *use dot notation and call **self* or another receiver.
class Person
def younger_than?(other_person)
self.age < other_person.age
end
protected
def age
@age
end
end
When do you use them?
The best time to create a method under the protected heading is when you want to compare and/or transfer data between objects of the same class, but you don’t want that information to be made public.
Say I’m building a banking game and I want to keep the account balance information private. However, I want to include features that let me know whether I have more money than a friend and to steal from them.
class BankAccount
def initialize
@balance = rand(100)
end
def richer_than(other_account)
if balance > other_account.balance
puts "You're rich!"
else
puts "Better luck next time."
end
end
def steal_from(other_account, amount)
if amount > other_account.balance
puts "Hold it there, they aren't that rich."
return
else
@balance = @balance + amount
other_account.balance = other_account.balance - amount
return
end
end
protected
def balance
@balance
end
def balance=(num)
@balance = num
end
end
my_account = BankAccount.new
friend_account = BankAccount.new
my_account.richer_than(friend_account)
# => "Better luck next time."
my_account.steal_from(friend_account, 25)
my_account.richer_than(friend_account)
# => "You're rich!"
my_account.balance # => NoMethodError
Let’s break down the above code.
I made the balance getter method protected, so it is not available to the public scope and there’s no way of actually knowing how much money is in the account.
The richer_than method takes another BankAccount object as an argument and lets you know if your own account has more money than theirs.
The steal_from method takes two arguments, a BankAccount object and how much money to take from it. However, since you don’t know how much money the other bank account has, you have to make a guess of how much to take. That is why it lets you know if you’ve taken too much.
Finally, I invoke the getter balance method at the end just to reiterate that calling a protected method will result in an error.
Summary
Public instance methods:
- Accessible from global scope.
- Part of the class interface.
- All instance methods are public by default.
- Use if displaying information or interacting with other classes and/or the client.
Private instance methods:
- Accessible only from within class scope.
- Part of the class inner-workings.
- Must preface with private method.
- Use when hiding sensitive information or crucial class methods.
Protected instance methods:
- Accessible from within class scope and by objects of the same class.
- Must preface with protected method.
- Use when wanting to compare/interact with other class objects, but don’t want the program or client to have access to them.
There you have it. An in-depth look at public, private and protected methods. I hope this has been as helpful to you as it has been to me.
Now go and make some awesome object oriented programs!
Top comments (1)
The answer is simple: if you ever think of using
private
you are wrong, and you should change your mind.Languages with
private
are a whole lot more annoying to work in, because of people who useprivate
think they're smart enough to make that decision. Then there's a bug, that could easily be fixed by extending the class and calling a protected function, or similar and instead you have to fork their code to fix it, and if the dependency tree is large enough it becomes pretty much impossible. Sometimes you can at least use reflection to call "private" functions regardless.This has happened countless times over an extended period of time and will never cease to happen, because people will never stop thinking they are smarter than they are.
Simply put, imo
private
keyword should not exist in any languages, andprotected
should be changed to mean "you should not normally call this, but call it if you think you really need to".