Public vs. Private vs. Protected
Tags: tutorial, ruby, oop
Published: 2021-01-08 17:49:07

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](https://launchschool.com/books/oo_ruby).

![](https://cdn-images-1.medium.com/max/2000/1*vh86XcGIFy95MZB1Z3Pzzw.gif)

## 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:

```ruby
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.](https://cdn-images-1.medium.com/max/2000/1*hQ1Z4gB6BUTMpOeHSnWUeg.gif)*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:

```ruby
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:

```ruby
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.

```ruby
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.

```ruby
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.

```ruby
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.

```ruby
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.

![](https://cdn-images-1.medium.com/max/2000/1*wMjBR8cOrCOBwumPI1Y7CQ.gif)

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!