OOP, the right way: Message Passing and the Four Pillars
Tags: oop, programming
Published: 2024-01-22 13:08:06

I just watched [an old video of ThePrimeagen](https://www.youtube.com/watch?v=STtOP6d7K_4) about message passing in OOP, and I wanted to write an article that explained the topic better. So here we are.

Message passing, for those who don't know, is essentially a trigger for an object to act. Somehow, "message passing" became "method calls". Javascript, despite not being [Smalltalk](https://en.wikipedia.org/wiki/Smalltalk), already has a nice mechanism for messages, though. You can access an object's fields dynamically:

```js
obj['message'](...params);
```

This allows you to access the behavior associated with the message. Behavior is not the same as a method call. Behaviors can be many private methods at once, public methods or even reference usage of other objects. What matters is the declarative API that message passing enables. This attains the principle of `Abstraction`.

```js
const jose = new Person('José');

jose['greet'](); // prints "Hello, I am José!"
jose['sum'](2, 2); // prints "I am bad at math!!!"
```

If we give the same message to different objects, what happens? We get `Polymorphism`.

```js
const jose = new Person('José');
const fusca = new Car('Fusca');
const pimenta = new Dog('Pimenta');

jose['greet'](); // prints "Hello, I am José!"
fusca['greet'](); // prints "Beep!"
pimenta['greet'](); // prints "Woof!"
```

To teach José some math, we can't simply open José's brain and shove math inside it — it isn't how brains work in real life, so it won't be how we model our system here. José will be properly taught. Let's introduce him to Maria, a teacher:

```js
const jose = new Person('José');
const maria = new Teacher('Maria'); // Note the new class

maria['greet'](jose); // prints "Hello, José, I am Maria!"

jose['greet-back'](maria); // prints "Hello, Maria, nice to meet you!"

// José even knows how to `greet-back` — how fancy.
```

See how the `greet` message is different this time? Behaviors can be modified with parameters. This is also a great example of the principle of `Inheritance`: A teacher is a person, and all persons know how to greet. Maria, being a teacher and person, knows how to greet too.

Finally, let's teach José some math:

```js
// Checking again if José knows math:

jose['sum'](2, 2); // prints "I am bad at math!!!" still!

// Nothing new. Let's have Maria to teach him:
maria['teach'](jose, 'math');

jose['sum'](2, 2); // prints "2 plus 2 is 4."
```

What happened with José? Did Maria just shove math into his brain? Let's take a look at the `teach` behavior below. Since objects cannot change the state of other objects, you must pass the message and let them deal with it.

```js
class Teacher extends Person {
  // ... other logic goes here

  teach(person, subject) {
    person['learn'](subject);
  }
}
```

That rule of not touching the internal state of another object is called `Encapsulation`. Only José can truly learn — Maria can only help. José is a good student and, now that he knows math, he behaves differently when prompted to sum two numbers.

And there you have it: We explored the four pillars of Object Oriented Programming through the lenses of Message Passing. 

Hope you enjoyed it!