Process communication in Elixir
Tags: elixir, process, otp, erlang
Published: 2021-10-21 18:26:46

The focus of this post is to explain the communication between processes in elixir in a simple way. [Here](https://dev.to/thiagoslima/comunicacao-entre-procesos-em-elixir-47m0) you can read the portuguese version of this article. When you've finished reading, you'll have a basic understanding of how to create processes and how they send and receive messages.

## How to create processes

A process is something that can do things in isolation and concurrently. Well... this is pretty vague. Let's try a more concrete example. Let's say you are a mouse process. You can do many things that mice do, like hiding or eating cheese for example. You are independent, you don't need other people to do what you want and they don't interfere with your activities. That is, you do it in isolation. In a mice contest to see who eats the most cheese, everyone could do it concurrently and in parallel. Everyone eats at the same time and not one at a time.

![A mouse process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8x0yqkn8ojce5ltesq0.jpg)

Now that we have an idea of what a process is, let's imagine that you want to make a new friend, that is, another process. So let's create the cat process. We can do this with the `spawn` function.

![Spawn a new process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acjwvqzkm40vl010uggh.jpg)

The spawn function creates a new process and performs a function on it. It has two arities: `spawn/1` takes a function and `spawn/3` takes a module, a function as an atom and a list of parameters. Here we are going to use the second form because we are going to define `Cat` in a module. The `create` function just prints a message. You can put the code below in a file called `mouse.exs` and run it with `elixir mouse.exs`. If you do this you will see the commented result.

```elixir
# mouse.exs
defmodule Cat do
  def create do
    IO.puts("You create cat")
  end
end

# Here you create a cat
spawn(Cat, :create, [])

# Result:
# "You create cat"
```

## Communication between processes

After creating a new process, your friend the cat, you want to talk to him. But remember that processes are isolated. Imagine that everyone lives in their own home with social distance. So how to communicate with him? Millions of years ago people used a form of communication called mail. Processes communicate in a similar way. So to talk to your friend you will send a message like that.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/efxih82gwhasnpysdq7t.jpg)

### Sending and receiving messages

We send a message with the `send/2` function. We pass to this function two things: the **receiver** and the **message**. But how will our code know how to send the message to the cat process? Thankfully, the `spawn` function returns an identifier of the process created for us, as if it were its address. So let's save the `spawn` return in the variable `cat`.

```elixir
cat = spawn(Cat, :create, [])
```

The cat needs to know how to receive this message. For this we defined the `receive` block. Here's how it works: the cat will look inside the mailbox and decide what is important. That is, for which messages he wants to do something.

```elixir
# mouse.exs
defmodule Cat do
  def create do
    receive do
      :how_is_it_going -> IO.puts("Good!")
    end
  end
end

# Here you create a cat
cat = spawn(Cat, :create, [])

# Send the message
send(cat, :how_is_it_going)

# Result:
# "Good!"
```

## Answering back

Our code has a problem. Imagine `IO.puts("Good!")` as if the cat had said that. But you are in your own homes, remember? So you didn't hear his answer. Because processes communicate with messages, he would have to send you a message back.

![Send message back](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bh57aizye65ezxtezg2x.jpg)

Glad you already know how to send a message. Just make the cat respond with `send(mouse, :good)` and it's all right! However, how will the cat know that the message came from the mouse? To do this, let's say in the message who the `sender` was. We have to change the cat's `receive` to care for messages that follow the pattern `{:how_is_it_going, sender}`. So he can reply to the right person with `send(sender, :good)`. It looks like this:

```elixir
receive do
  {:how_is_it_going, sender} -> send(sender, :good)
end
```

Now the mouse needs to identify itself to send the message `send(cat, {:how_is_it_going, mouse})`. Remember that the mouse is the **current process**. To identify the current process in the code we use the `self/0` function. It's like we're getting our own address. So we save its return in a variable `mouse = self()`.

```elixir
# This is you
mouse = self()

# Send the message
send(cat, {:how_is_it_going, mouse})
```

Almost everything is ready. We just need to look in the mouse's mailbox for the message the cat sent and decide what to do. The entire code would look like this:

```elixir
# mouse.exs
defmodule Cat do
  def create do
    receive do
      {:how_is_it_going, sender} -> send(sender, :good)
    end
  end
end

# This is you
mouse = self()

# Here you create a cat
cat = spawn(Cat, :create, [])

# Send the message
send(cat, {:how_is_it_going, mouse})

# Look in the mouse's mailbox
receive do
  :good -> IO.puts("Nice!")
end

# Result:
# "Nice!"
```

## Temporary Process

You can check whether a process is alive with the `Process.alive?/1` function. Let's run the same code above but see when the cat process is alive by adding `IO.puts("Is the cat alive? #{Process.alive?(cat)}")`.

```elixir
# mouse.exs
defmodule Cat do
  def create do
    receive do
      {:how_is_it_going, sender} -> send(sender, :good)
    end
  end
end

# This is you
mouse = self()

# Here you create a cat
cat = spawn(Cat, :create, [])

IO.puts("Is the cat alive? #{Process.alive?(cat)}")

# Send the message
send(cat, {:how_is_it_going, mouse})

# Look in the mouse's mailbox
receive do
  :good -> IO.puts("Nice!")
end

IO.puts("Is the cat alive? #{Process.alive?(cat)}")

# Result:
# Is the cat alive? true
# Nice!
# Is the cat alive? false
```

We can see that the process was alive, but after answering it died. Why did this happen?

![Dead process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tzi7l2nm9o120icvnie7.jpg)

To understand what happened let's look at the `create` function. Here we defined a `receive` block. Since the mouse received the message back, communication is correct. But what happens after the cat responds? **Nothing** else happens in the cat process. As such, it no longer needs to exist and the process dies!

```elixir
def create do
  receive do
    {:how_is_it_going, sender} -> send(sender, :good)
  end
end
```

## Permanent Process

To keep the process alive, let's make sure it doesn't respond to **just one message**. It will keep checking messages and replying. We can do this by defining the `check_messages/0` function and passing the `receive` block to it.

```elixir
def create do
  check_messages()
end

def check_messages do
  receive do
    {:how_is_it_going, sender} -> send(sender, :good)
  end

  check_messages()
end
```

So the only thing the create function does is to tell the cat to check the messages. Now look at the last line of `check_messages/0`. It calls itself! That is, whenever it ends, it goes back to the beginning. It's a **recursive function**. That way the cat checks messages forever and doesn't die. The whole code looks like this:

```elixir
# mouse.exs
defmodule Cat do
  def create do
    check_messages()
  end

  def check_messages do
    receive do
      {:how_is_it_going, sender} -> send(sender, :good)
    end

    check_messages()
  end
end

# This is you
mouse = self()

# Here you create a cat
cat = spawn(Cat, :create, [])

IO.puts("Is the cat alive? #{Process.alive?(cat)}")

# Send the message
send(cat, {:how_is_it_going, mouse})

# Look in the mouse's mailbox
receive do
  :good -> IO.puts("Nice!")
end

IO.puts("Is the cat alive? #{Process.alive?(cat)}")

# Result:
# Is the cat alive? true
# Nice!
# Is the cat alive? true
```

# Conclusion

Here you learned the basics of how to create processes with `spawn`. How they send messages with `send/2` and receive messages with the `receive` block. You saw a little bit about how a process can die and how to keep it alive. And the best of all, cats and mice can be friends after all!

## Resources

- You can find all the source code in this [repo](https://github.com/ThiagosLima/process_communication_en).
- [This](https://dev.to/thiagoslima/comunicacao-entre-procesos-em-elixir-47m0) is a portuguese version of the article.
- For more information about process, you can access the official [guide](https://elixir-lang.org/getting-started/processes.html).
- The documentation of the used functions:
  - [spawn](https://hexdocs.pm/elixir/Kernel.html#spawn/1)
  - [send](https://hexdocs.pm/elixir/Kernel.html#send/2)
  - [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1)
  - [self](https://hexdocs.pm/elixir/Kernel.html#self/0)
  - [IO.puts](https://hexdocs.pm/elixir/IO.html#puts/2)
  - [Process.alive?](https://hexdocs.pm/elixir/Process.html#alive?/1)