Skip to content
Spawn and Self-Loops
step 1/5

Reading — step 1 of 5

Learn

~1 min readProcess Patterns

Stateful Erlang processes use tail-recursive loops. The function calls itself with new state at the end of each iteration.

-module(main).
-export([main/1]).

start() ->
    spawn(fun() -> loop(0) end).

loop(N) ->
    receive
        increment -> loop(N + 1);
        {get, From} ->
            From ! {value, N},
            loop(N);
        stop -> ok
    end.

main(_) ->
    Pid = start(),
    Pid ! increment,
    Pid ! increment,
    Pid ! increment,
    Pid ! {get, self()},
    receive
        {value, V} -> io:format("~w~n", [V])
    end.

Key points:

  • The loop/1 function is tail-recursive — Erlang optimizes this to constant stack space.
  • Each branch of receive either calls loop again (with potentially new state) or returns (terminating the process).
  • From ! Msg sends a message. self() is the current process's PID.
  • The receiver pattern-matches on a unique tag ({value, N}) to know what message to receive.

Synchronous request/reply: The "send a message including self(), then receive a reply" pattern is so common that it has a name: a synchronous call. Real Erlang code uses gen_server:call to wrap it.

Selective receivereceive only matches messages whose patterns match. Other messages stay in the mailbox:

receive
    {priority_task, T} -> handle_priority(T)
after 0 ->
    %% skip if no priority message right now
    ok
end

The after Timeout clause runs if no message arrives within Timeout ms. after 0 is non-blocking.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…