Pointers in Elixir

Elixir supports the concept of processes and message passing, which are somewhat analogous to pointers in terms of sharing and modifying data. We’ll demonstrate this using two functions: zero_val and zero_pid.

defmodule Pointers do
  def zero_val(val) do
    _new_val = 0
  end

  def zero_pid(pid) do
    send(pid, :zero)
  end

  def run do
    i = 1
    IO.puts("initial: #{i}")

    zero_val(i)
    IO.puts("zero_val: #{i}")

    pid = spawn(fn -> loop(i) end)
    zero_pid(pid)
    :timer.sleep(100)  # Give some time for the message to be processed
    send(pid, {:get, self()})
    receive do
      {:value, value} -> IO.puts("zero_pid: #{value}")
    end

    IO.puts("pid: #{inspect(pid)}")
  end

  defp loop(value) do
    receive do
      :zero ->
        loop(0)
      {:get, sender} ->
        send(sender, {:value, value})
        loop(value)
    end
  end
end

Pointers.run()

In this Elixir example, we’ve created two functions to demonstrate the difference between passing values and using processes (which are Elixir’s lightweight threads):

  1. zero_val takes a value as an argument. It assigns 0 to a new variable, but this doesn’t affect the original value.

  2. zero_pid takes a process ID (PID) as an argument. It sends a message to the process, which can change its internal state.

In the run function:

  1. We create an initial value i = 1.

  2. We call zero_val(i), which doesn’t change the value of i.

  3. We spawn a new process that runs the loop function with the initial value of i. This process can receive messages to change its state or return its current value.

  4. We call zero_pid(pid), which sends a message to the process to change its internal value to 0.

  5. We then send a message to get the current value from the process and print it.

  6. Finally, we print the PID of the spawned process.

The loop function demonstrates how a process can maintain state and respond to messages. It can receive a :zero message to set its value to 0, or a :get message to send its current value back to a requester.

When you run this program, you should see output similar to this:

initial: 1
zero_val: 1
zero_pid: 0
pid: #PID<0.123.0>

This demonstrates that zero_val doesn’t change the original value, while zero_pid effectively changes the state of the process. The PID is a unique identifier for the spawned process.

In Elixir, processes and message passing are used for managing shared state and concurrency, serving a similar purpose to pointers in languages like C or Go, but with different semantics and safety guarantees.