1
votes

I am new learner on Erlang, I have questions about Erlang variable's life cycle.

Reference from Erlang gen_server comunication

-module(wy).
-compile(export_all).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-behaviour(gen_server).
-record(state, {id ,m, succ, pred}).

start(Name, M) ->
    gen_server:start_link({local, Name}, ?MODULE, [Name, M], []).

init([Name, M]) ->
    {ok, #state{id = Name, m = M}}.

handle_call({get_server_info}, _Frome, State) ->
    {reply, State, State};
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.


get_server_info(ServerName) ->
    gen_server:call(ServerName, {get_server_info}).

What is the Variable "State" life cycle?

We can see variable "State" is reused from handle_call and handle_cast. First of all, are these "State" is the same one which is initialized from init() function "#state{id = Name, m = M}"?

If so, is this "State" a global variable? When will this "State" be destroyed.

Does Erlang have global variables?

2

2 Answers

3
votes

Your intuition is correct, although I think it's worth pointing out that the variable State is technically not the same everywhere but it does reference the same value everywhere. Each of your callbacks (i.e. inti/1, handle_call/3, etc.) receive State as a parameter and they must return a (possibly new) State as part of their results.

To understand how this works, you need to know what gen_server does. In an super-extremely-oversimplified way, what gen_server is doing when you call gen_server:start_link/4 is:

% Ignoring stuff here, for simplicity
start_link(_Name, Mod, InitArg, _Options) ->
  spawn(
    fun() ->
      {ok, State} = Mod:init(InitArg),
      loop(Mod, State) %% This is where the result of your init/1 function goes
    end).

loop(Mod, State) ->
  NextState =
    receive
      {call, From, Msg} ->
        % Here, it gives you the current state and expects you to return
        % a new one.
        {reply, Reply, NewState} = Mod:handle_call(Msg, From, State),
        NewState;
      {cast, Msg} ->
        % Here, it gives you the current state and expects you to return
        % a new one.
        {noreply, NewState} = Mod:handle_cast(Msg, State),
        NewState;
      Info ->
        % Here, it gives you the current state and expects you to return
        % a new one.
        {noreply, NewState} = Mod:handle_info(Msg, State),
        NewState;
      {stop, Reason} ->
        Mod:terminate(Reason, State),
        exit(Reason)
    end,
  loop(Mod, NextState). % Then it keeps on looping with the new state

As you can see, the value of the State is local to the gen_server process, it is passed to each callback and it's replaced with the result of each callback to keep looping until the server is terminated. Of course, gen_server's code is not that simple (This talk provides a great explanation for this - in Spanish, I know, sorry).

Hope this helps :)

0
votes

State is the internal state of the gen_server. State can be anything, a single variable to data structure (map, record or list), in this case a record. use record if you have defined set of values, otherwise we can use a map.

Yes, State will initialized in init() function and will be passes as a parameter in each callbacks, you can simply update State value according to your need and set is as new State when sending reply in each callbacks.

State will destroyed along with gen_server process, if gen server killed or exit normally. when exiting with reason normal terminate/3 callback will be called.