A line number generator closure in Pony Lang

I had taken a look at Pony Lang a few years back, and I had found that it had a lot of very interesting ideas about it that warranted a closer and deeper look.

Unfortunately, the documentation was quite subpar in those days, and I quickly lost interest in the project. A while back, I heard new that Sylvan Clebsch (the author of the Pony language) had moved on to Microsoft, and that led me to wondering about the state of the project.

Surprisingly, I found that the language had managed to garner itself quite a community of enthusiasts and even some industry support (thanks in a very large part to Sean T. Allen and co.). This rekindled my interest in Pony, and I have decided to seriously pursue the language this time around.

In that spirit, I present my first attempt at a relatively interesting program in Pony (I am still an abject beginner in Pony!), much as I have done with other languages that piqued my interest:

class LineNumGenerator
  var _env: Env
  
  new create(env: Env) =>
    _env = env
    
  fun new_line_num_closure(): {ref()} =>
    var linum = USize(0)
    
    {ref()(env = _env) =>
       linum = linum + 1
       env.out.print("Line number = " + linum.string())
    }
    
actor Main
  new create(env: Env) =>
    let a_linum_func = LineNumGenerator(env).new_line_num_closure()
    
    var ctr = U32(0)
    while ctr < 10 do
      a_linum_func()
      ctr = ctr + 1
    end
    
    env.out.print("")
    
    let another_linum_func = LineNumGenerator(env).new_line_num_closure()
    
    ctr = U32(0)
    while ctr < 5 do
      another_linum_func()
      ctr = ctr + 1
    end
    

And running it, we get the expected output:

Line number = 1
Line number = 2
Line number = 3
Line number = 4
Line number = 5
Line number = 6
Line number = 7
Line number = 8
Line number = 9
Line number = 10

Line number = 1
Line number = 2
Line number = 3
Line number = 4
Line number = 5

Very satisfying, especially the blazingly fast compilation speeds of Pony (thus far – I hope to see similar performance when I get around to some actual projects in it).

The bulk of the core language still lies ahead of me – Reference & Object Capabilities, Generics, Pattern Matching, and C-FFI in particular. This should be an interesting journey!

Simple comparison of a calculator process written using concurrency primitives vs using GenServer (Elixir)

I have been working through Saša Jurić ‘s excellent book, “Elixir in Action” (Manning publications), and having reached GenServers, I thought it might be a nice exercise to implement a simple calculator process (stateful server) from First Principles and then show how that translates (rather smoothly) into the same example using the GenServer module.

Here is the example server written from the ground up:

defmodule ServerProcess do
  def start(callback_module) do
    spawn(fn ->
      initial_state = callback_module.init()
      loop(callback_module, initial_state)
    end)
  end

  def call(server_pid, request) do
    send(server_pid, {:call, self(), request})

    receive do
      {:response, response} -> response
    after
      5000 -> IO.puts("Timeout while awaiting response")
    end
  end

  def cast(server_pid, request) do
    send(server_pid, {:cast, request})
  end

  defp loop(callback_module, current_state) do
    receive do
      {:call, caller, request} ->
	{response, new_state} = callback_module.handle_call(request, current_state)
	send(caller, {:response, response})
	loop(callback_module, new_state)

      {:cast, request} ->
	new_state = callback_module.handle_cast(request, current_state)
	loop(callback_module, new_state)
    end
  end
end

defmodule Calculator do
  # interface functions

  def start do
    ServerProcess.start(Calculator)
  end

  def add(server_pid, value) do
    ServerProcess.cast(server_pid, {:add, value})
  end

  def sub(server_pid, value) do
    ServerProcess.cast(server_pid, {:sub, value})
  end

  def mul(server_pid, value) do
    ServerProcess.cast(server_pid, {:mul, value})
  end

  def div(server_pid, value) do
    ServerProcess.cast(server_pid, {:div, value})
  end

  def value(server_pid) do
    ServerProcess.call(server_pid, :value)
  end

  # implementation (callback) functions
  
  def init do
    0
  end

  def handle_cast({:add, value}, state) do
    state + value
  end

  def handle_cast({:sub, value}, state) do
    state - value
  end

  def handle_cast({:mul, value}, state) do
    state * value
  end

  def handle_cast({:div, value}, state) do
    state / value
  end

  def handle_call(:value, state) do
    {state, state}
  end
end

Running it:

iex(26)> pid = Calculator.start
pid = Calculator.start
#PID
iex(27)> Calculator.add(pid, 10)
Calculator.add(pid, 10)
{:cast, {:add, 10}}
iex(28)> Calculator.sub(pid, 5)
Calculator.sub(pid, 5)
{:cast, {:sub, 5}}
iex(29)> Calculator.mul(pid, 3)
Calculator.mul(pid, 3)
{:cast, {:mul, 3}}
iex(30)> Calculator.div(pid, 3)
Calculator.div(pid, 3)
{:cast, {:div, 3}}
iex(31)> Calculator.value(pid)
Calculator.value(pid)
5.0

And now the very same server simply using the generic GenServer module:

defmodule Calculator do
  use GenServer

  # interface functions
  
  def start do
    GenServer.start(Calculator, nil) # returns {:ok, pid}
  end

  def add(server_pid, value) do
    GenServer.cast(server_pid, {:add, value})
  end

  def sub(server_pid, value) do
    GenServer.cast(server_pid, {:sub, value})
  end

  def mul(server_pid, value) do
    GenServer.cast(server_pid, {:mul, value})
  end

  def div(server_pid, value) do
    GenServer.cast(server_pid, {:div, value})
  end

  def value(server_pid) do
    GenServer.call(server_pid, :value)
  end

  # implementation (callback) functions
  
  def init(_) do
    {:ok, 0}
  end

  def handle_call(:value, _caller, state) do
    {:reply, state, state}
  end

  def handle_cast({:add, value}, state) do
    {:noreply, state + value}
  end

  def handle_cast({:sub, value}, state) do
    {:noreply, state - value}
  end

  def handle_cast({:mul, value}, state) do
    {:noreply, state * value}
  end

  def handle_cast({:div, value}, state) do
    {:noreply, state / value}
  end
end

Again, running it:

iex(35)> {:ok, pid} = Calculator.start
{:ok, pid} = Calculator.start
{:ok, #PID}
iex(36)> Calculator.add(pid, 10)
Calculator.add(pid, 10)
:ok
iex(37)> Calculator.sub(pid, 5)
Calculator.sub(pid, 5)
:ok
iex(38)> Calculator.mul(pid, 3)
Calculator.mul(pid, 3)
:ok
iex(39)> Calculator.div(pid, 3)
Calculator.div(pid, 3)
:ok
iex(40)> Calculator.value(pid)
Calculator.value(pid)
5.0

A massive reduction in code size, and arguably (assuming that one already knows how the primitive version works), much simpler to understand!

I am loving Elixir thus far, and Saša Jurić is a brilliant teacher. I wholeheartedly recommend this book to anyone looking to learn Elixir. Make sure to get the 2019 revised edition though!