# [003.1] Preparing to Learn about OTP

A solution to the Reverse Polish Notation Calculator exercise, and preparatory readings for learning about OTP.

### Preparing to Learn about OTP [02.13.2017]

In the last episode, you were provided an exercise to create a Reverse Polish Notation Calculator process. Today we'll look at a solution, as well as some readings to prepare to learn more about OTP. Let's get started.

## Exercise Solution

It's good to go through the exercise piece by piece and test-drive the solution. When you first pull down the `rpn` repo, tagged before this episode and run the tests, you'll find that none pass of course. We can focus on the first test:

``````  test "starts with an empty stack" do
{:ok, pid} = Rpn.start
assert Rpn.peek(pid) == []
end
``````

This says that if we evaluate the `peek` function with our process id as an argument, we should get back an empty list. Let's implement that, with a public function to send the message and a case statement for the process receive block:

``````defmodule Rpn do
def start do
{:ok, spawn(__MODULE__, :loop, [[]])}
end

def loop(stack) do
receive do
# We'll receive a message from another process, with a ref, and the atom
# `peek`. We will then send back a 2-tuple containing the ref they sent
# and the value of our stack.
{from, ref, :peek} ->
send(from, {ref, stack})
loop(stack)
end
end

# We'll provide a function that makes it easy to send the message the loop is
# waiting for and then enters a receive loop of its own, awaiting a reply. The
# reason we make these unique references, by the way, is because anyone could
# send us a message at any time, and if it matched the pattern we were looking
# for we would accept it - this way we only match the message we're hoping to
# get back.
def peek(pid) do
ref = make_ref()
send(pid, {self(), ref, :peek})
# Once we receive the value, we just return it.
receive do
{^ref, val} -> val
end
end
# ...
end
``````

That's enough code to make the first test pass. Let's move on to the second test:

``````  test "pushing onto the stack" do
{:ok, pid} = Rpn.start
Rpn.push(pid, 5)
assert Rpn.peek(pid) == [5]
Rpn.push(pid, 1)
assert Rpn.peek(pid) == [1, 5]
end
``````

This test says we can push items onto the stack and see them there. It's easy enough to make this work - we just accept a `push` message that includes a value, and put it into our internal state:

``````defmodule Rpn do
# ...
def loop(stack) do
receive do
# ...
# When someone pushes a value, we just create a new list with that value
# at the front of it and loop.
{:push, val} ->
loop([val | stack])
end
end
# ...
# And we make it easy to push a new value.
def push(pid, val) do
send(pid, {:push, val})
end
end
``````

Alright, so now we have two tests passing. Next, we need to support adding:

``````  test "adding" do
{:ok, pid} = Rpn.start
Rpn.push(pid, 5)
Rpn.push(pid, 1)
Rpn.push(pid, :+)
assert Rpn.peek(pid) == [6]
end
``````

When we get to the point that we push the `:+` onto the stack, we have two numbers already. We just need to pull them off the stack and push the result of adding them together back onto the stack.

We'll handle the atom `+` as a value higher up in our receive block, so that it takes precedence. When the value is `:+`, we pattern match out the top two items from the stack, add them together, and push the result onto the stack in their place. Note that their order is reversed here - second, then first. That's important when you get to an operator that cares about ordering.

``````  def loop(stack) do
receive do
# ...
{:push, :+} ->
[second | [first | rest]] = stack
loop([first + second | rest])

{:push, val} ->
loop([val | stack])
end
end
``````

From here, implementing subtraction and multiplication is easy:

``````  def loop(stack) do
receive do
# ...
{:push, :-} ->
[second | [first | rest]] = stack
loop([first - second | rest])

{:push, :x} ->
[second | [first | rest]] = stack
loop([first * second | rest])

{:push, val} ->
loop([val | stack])
end
end
``````

And with that, the whole test suite passes. There are definitely other ways you could have implemented it, but this is how I'd go about it. You can find my full solution here. You'll note that I didn't implement division - that's because no tests called for it! :)

## Preparatory Readings

This week we'll be looking at OTP in depth. OTP stands for Open Telecom Platform, which is a collection of middleware and libraries in Erlang. We'll cover the most prominent parts of OTP:

• GenServer
• This is a generic server process. It formalizes some of the things we've done til now to talk to processes, as well as adds support for supervision, which is how Elixir and Erlang programs achieve their high availability. It also provides facilities for tracing and error reporting that bare processes don't have.
• Supervisor
• A supervisor supervises other processes - its children. Supervisors define your application's hierarchy and they are the backbone of fault-tolerance within OTP.
• GenStateMachine
• The standard library from Erlang provides `gen_statem`, which is a state machine behaviour. We'll use the `GenStateMachine` package for state machines, as it yields a better experience in Elixir.