← All Examples Concurrency

Concurrent Counter

A counter running in its own lightweight process, receiving typed messages. This demonstrates JAPL's Erlang-inspired actor model with type-safe message passing.

Source Code

type Msg =
  | Inc
  | Get

fn counter(n: Int) {
  println("Counter value: " <> show(n))
  receive {
    Inc => counter(n + 1)
    Get => println("Final: " <> show(n))
  }
}

fn main() {
  println("Starting concurrent counter...")
  let pid = spawn(fn() { counter(0) })
  send(pid, Inc)
  send(pid, Inc)
  send(pid, Inc)
  send(pid, Get)
  println("Messages sent.")
}

What This Demonstrates

Line-by-Line Breakdown

type Msg = | Inc | Get
Defines the message protocol for the counter process. Only Inc and Get messages are valid.
fn counter(n: Int)
The process function. It prints the current value, then waits for a message.
receive { Inc => counter(n + 1) ... }
Blocks until a message arrives. On Inc, it recurses with n + 1, keeping the process alive. On Get, it prints the final value and terminates (no recursive call).
let pid = spawn(fn() { counter(0) })
Spawns a new process running counter(0). Returns a process identifier (pid) used to send messages.
send(pid, Inc)
Sends an Inc message to the counter process. This is asynchronous -- execution continues immediately.

Try Modifying