Swift's POP (Protocol Oriented Programming) paradigm in rea life
Tags: swift, pop
Published: 2023-01-03 14:19:43

## Introduction

Imagine we want to implement a sort of postal system, where messages can be _sent_ from _someone_ to the post office; where it will be accordingly _dispatched_ to the right destination. 

## Beginning 
We could go ahead and define a simple _data model_, that represents a _message_.
This entity holds the _actual_ message (we'll call it _content_), and some meta-data, i.e. data about the message itself.

Since we want this message to be _immutable_ and we don't want _shared references_ of it, we can make it a _struct_, as opposed to a class:

```swift
struct Message {
   // the meta-data; who is sending this message
   let sender: String
   // also meta-data; the receiver of the message
   let to: String 
   // the actual content of the message
   let content: String
}
```

## The Dispatcher 

Now that we have a data model, which will be a shared entity between _sender_ (a person) and _dispatcher_ (the postal office).
We can go ahead and imagine our _dispatcher_:

```swift
class Dispatcher {
    public func dispatch(_ message: Message) {
       print("Sending \(message.content) to \(message.to) from \(message.from)")
    }
}
```
## The Sender
Finally let's imagine the person sending the message:

```swift
class Person {
     private unowned let dispatcher: Dispatcher
     let name: String
     init(dispatcher: Dispatcher, ) {
        self.dispatcher = dispatcher
        self.name = name
     }

     public func sendMessage(of message: Message) {
         dispacher.dispatch(message)
   }
}
```
## Example
This looks ok. Let's see how it will look in practice:

 ```swift
    let dispatcher = Dispatcher()
    let helvidius = Person(dispatcher: dispatcher, name: "Helvidius")
    let jovinian = Person(dispatcher: dispatcher, name: "Jovinian")
    
   helvidius.sendMessage(of: Message(sender: helvidius.name, to: "Jovinian", content: "Hi Jovinian! How are you?"))
 ```

## The actual problem
Notice however, it's a bit odd that Bob has to specify he's the sender. 
A person has a name, and if a person _sends_ a message, he's _always_ going to be the sender.
In fact, the current code could be exploited, supposing we'd offer anyone the ability to send messages (i.e. Person class would be a public API):
 ```swift
    let dispatcher = Dispatcher()
    let evilMike = Person(dispatcher: dispatcher, name: "Evil Mike")    
   evilMike.sendMessage(of: Message(sender: "Andy", to: "Sandy", content: "Hi Sandy! I'm Andy, and I think you look ugly!"))
 ```

## The solution!
Protocols could make our lives much more easy. To start, we've noticed every person has a name; it also s seems maybe not just persons can send messages. why not have machines be able to send messages as well? All we need after all, besides the content and receiver, is for the sender to _identify_ himself.
We could use Swift's _UUID_ type, and that would be a great idea! However, for the sake of simplicity, well stick to a name field, of type string:

```swift
protocol Sender {
   var name: String { get }
}
```
Great! Now we could have a ton of other types that can be senders, like machines:
```swift
class Machine: Sender {
   let name: String
   let dispacher: Dispatcher
   
   init(name: String, dispathcer: Dispathcer) {
       self.name = name
       self.dispathcer = dispatcher
   }

   public sendHappyNewYear() {
       let date = Date.now

       let components = Calendar.current.dateComponents([.month, .day], from: date)

         if components.day == 1 && components.month == 1 {
                dispatcher.dispatch(Message(sender: "Robot1", to: "Sandy", content: "Happy new Year Sandy!"))
         }

   }
}
```

However, the actual problem still remains, just about anyone can create a message and pretend to be someone else!
So here's where POP (Protocol Oriented Programming) comes more handy in place. 

We can make the initializer (or constructor, if you will) of Message entity fileprivate!  

```swift
struct Message {
   // the meta-data; who is sending this message
   let sender: String
   // also meta-data; the receiver of the message
   let to: String 
   // the actual content of the message
   let content: String

   fileprivate init(sender: String, to: String, content: String) {
      self.sender = sender
      self.to = to
      self.content = content
   }
}
```
Great, now we can define an _extension_ method on the _Sender_ protocol. That is a method that anyone who's a sender, can automatically benefit from, even retroactively! I.e. entities that already conform to the Sender protocol before the extension method is introduced can benefit from!:

```swift
struct Message {
   ...
}

extension Sender {
   func createMessage(to receiver: String, content message: Message) -> Message {
    Message(sender: self.name, to: receiver, content: message)
}
}

```
Now any sender can call the `createMessage` method, that will automatically use the name the `Sender` has, because remember, the only thing we know about a `Sender` is that he has a name, and we can make use of that name in protocol extensions.