title: Erlang/OTP behaviors for beginner
body: <p>As I understood from the "Erlang and OTP in action" book, the word behavior refers to:</p>
  
  <ul>
  <li>the behaviour interface, which is a set of functions;</li>
  <li>the behaviour implementation, which is the application-specific code (a callback module);</li>
  <li>the behaviour container, which is a process.</li>
  </ul>
  
  <p><strong>Question:</strong></p>
  
  <p><em>What an Erlang/OTP beginner should know about behaviours? Is it possible to describe and understand the notion of OTP behaviour in a nutshell?</em></p>
  
  <p><em>What 'callback function' does actually mean in the context of Elang/OTP?</em></p>
  
  <p>Can we consider the callbacks in a behaviour implemenation as methods overriden in Java?</p>
  
  <p>The book says that the associated callback function for the library function 'gen_server:start_link/4' in the following code is 'Module:init/1'.</p>
  
  <p>Does that mean that with init/1 we call the gen_server:start_link/4 library function? Or does that mean anything else?</p>
  
  <pre><code>-module(tr_server).
  
  -behaviour(gen_server).
  
  -include_lib("eunit/include/eunit.hrl").
  
  %% API
  -export([
           start_link/1,
           start_link/0,
           get_count/0,
           stop/0
           ]).
  
  %% gen_server callbacks
  -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
           terminate/2, code_change/3]).
  
  -define(SERVER, ?MODULE).
  -define(DEFAULT_PORT, 1055).
  
  -record(state, {port, lsock, request_count = 0}).
  
  
  %%%===================================================================
  %%% API
  %%%===================================================================
  
  
  %%--------------------------------------------------------------------
  %% @doc Starts the server.
  %%
  %% @spec start_link(Port::integer()) -&gt; {ok, Pid}
  %% where
  %%  Pid = pid()
  %% @end
  %%--------------------------------------------------------------------
  start_link(Port) -&gt;
      gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []).
  
  %% @spec start_link() -&gt; {ok, Pid}
  %% @doc Calls `start_link(Port)' using the default port.
  s    tart_link() -&gt;
      start_link(?DEFAULT_PORT).
  
  %%--------------------------------------------------------------------
  %% @doc Fetches the number of requests made to this server.
  %% @spec get_count() -&gt; {ok, Count}
  %% where
  %%  Count = integer()
  %% @end
  %%--------------------------------------------------------------------
  get_count() -&gt;
      gen_server:call(?SERVER, get_count).
  
  %%--------------------------------------------------------------------
  %% @doc Stops the server.
  %% @spec stop() -&gt; ok
  %% @end
  %%--------------------------------------------------------------------
  stop() -&gt;
      gen_server:cast(?SERVER, stop).
  
  
  %%%===================================================================
  %%% gen_server callbacks
  %%%===================================================================
  
  init([Port]) -&gt;
      {ok, LSock} = gen_tcp:listen(Port, [{active, true}]),
      {ok, #state{port = Port, lsock = LSock}, 0}.
  
  handle_call(get_count, _From, State) -&gt;
      {reply, {ok, State#state.request_count}, State}.
  
  handle_cast(stop, State) -&gt;
      {stop, normal, State}.
  
  handle_info({tcp, Socket, RawData}, State) -&gt;
      do_rpc(Socket, RawData),
      RequestCount = State#state.request_count,
      {noreply, State#state{request_count = RequestCount + 1}};
  handle_info(timeout, #state{lsock = LSock} = State) -&gt;
      {ok, _Sock} = gen_tcp:accept(LSock),
      {noreply, State}.
  
  terminate(_Reason, _State) -&gt;
      ok.
  
  code_change(_OldVsn, State, _Extra) -&gt;
      {ok, State}.
  
  %%%===================================================================
  %%% Internal functions
  %%%===================================================================
  
  do_rpc(Socket, RawData) -&gt;
      try
          {M, F, A} = split_out_mfa(RawData),
          Result = apply(M, F, A),
          gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
      catch
          _Class:Err -&gt;
              gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
      end.
  
  split_out_mfa(RawData) -&gt;
      MFA = re:replace(RawData, "\r\n$", "", [{return, list}]),
      {match, [M, F, A]} =
          re:run(MFA,
                 "(.*):(.*)\s*\\((.*)\s*\\)\s*.\s*$",
                     [{capture, [1,2,3], list}, ungreedy]),
      {list_to_atom(M), list_to_atom(F), args_to_terms(A)}.
  
  args_to_terms(RawArgs) -&gt;
      {ok, Toks, _Line} = erl_scan:string("[" ++ RawArgs ++ "]. ", 1),
      {ok, Args} = erl_parse:parse_term(Toks),
      Args.
  
  
  %% test
  
  start_test() -&gt;
      {ok, _} = tr_server:start_link(1055).
  </code></pre>