Rishab Parmar
Rishab Parmar

Reputation: 419

Simple increment in erlang

I am looking to build simple erlang logic where an actor maintains the count of how many times it was invoked.

For example, here is the actor(many actors can be possible):

-module(actor).
-export([do_work/0]).

do_work() ->
    increment = increment + 1

Suppose I invoke actor (with some Pid: XYZ) 5 times, XYZ = 5 because it was executed 5 times. But in Erlang, variables are immutable. So if I do increment++ for the first run, I cannot store the new result in increment or do increment = increment + 1. How do I maintain the count because I cannot create new variables dynamically say, increment_iteration_1 = increment + 1 and then do increment_iteration_2 = increment1 + 1 and so on.....in code for 1000 iterations?

Upvotes: 1

Views: 207

Answers (1)

Wojtek Surowka
Wojtek Surowka

Reputation: 20993

Your question touches the main difference between Erlang and other popular languages. In order to maintain and update some state - as the counter in your example - in Erlang you need to do some specific things, which I describe below. (Other solutions, like using a database, I will skip here since I assume you want to know how to do state maintenance directly).

In Erlang what you call actor is called process. And yes, to maintain a state, you need a process. The code you presented, though named actor, is not a process. It is just a module, which means that it is just some code. To use a process you need to start it, keep it running, and communicate with it using messages. It may sound complicated, but Erlang standard library provides gen_server, which does most of the work for you.

The sample code implementing a counter with gen_server would look like that:

-module(actor).
-behaviour(gen_server).
-export([do_work/0, init/1, handle_cast/2, handle_call/3]).

do_work() ->
    gen_server:cast(actor_server, do_work).

init(_Arguments) ->
    {ok, 0}.

handle_cast(do_work, Counter) ->
    {noreply, Counter + 1}.

handle_call(_Msg, _From, Counter) ->
    {noreply, Counter}.

Now somewhere in your code you need to start your process with

gen_server:start_link({local, actor_server}, actor, [], [])

Then, whenever you call actor:do_work(), it will increment the counter.

Few things worth mentioning are:

  • actor is a callback module. Gen_server internally does the hard work and calls callback functions from your module when it needs
  • The init callback function is called once when your process starts. I used it here to initialise the counter.
  • The process is registered with the name actor_server. When do_work calls gen_server:cast internally it sends a message to the process registered under the actor_server name. If you need several processes doing the same counter separately, more housekeeping is required, which I will skip here.
  • The handle_call part, not used here, provides the functionality where you can receive a reply (e.g. updated counter) from the process.
  • calling gen_server:start_link directly is good for testing, but in real code you will have a supervisor starting the process for you

More information about gen_server you will find its documentation.

Upvotes: 4

Related Questions