defining behaviours (Re: Design Patterns for Erlang)

Ulf Wiger etxuwig@REDACTED
Thu Feb 15 10:40:02 CET 2001

On Thu, 15 Feb 2001, Richard Carlsson wrote:

>There is a recent Master's thesis about design patterns and Erlang:
>	/Richard Carlsson

Good thesis (I've just browsed it.)

I'm currently looking at how behaviours are defined.
Personally, I don't like the idea of poking into otp_internal.erl
in order to define a new behaviour. In practice, this means that 
users of OTP can't define their own patterns.

I would like to propose the following:

- The otp_internal:behaviours() function is simply scrapped.
  If a module defines a compiler directive -behaviour(B), then
  B should correspond to the name of the module implementing the

- In each behaviour, export a function B:behaviour_info(Category),
  for example like this:


behaviour_info(exports) ->
  [{init, 1}, {handle_call, 3}, {handle_cast, 2}, {handle_info, 2},
   {terminate, 2}, {code_change, 3}];
behaviour_info(_) ->

The catch-all clause is meant to facilitate additional categories.

Furthermore, I'd like to introduce the following requirement:

- A behaviour which wants a process must implement a function
  B:init_it/6, with the following arguments:

init_it(Starter, Parent, Name, Mod, Args, Options) ->
  ... % expected never to return

This is not a tough requirement to meet for existing behaviours.
Only two behaviours do not do this already: supervisor and 
supervisor_bridge. In supervisor_bridge, the function could look like

init_it(Starter, Parent, Name, Mod, Args, Options) ->
    IArgs = init_args(Args),
    gen_server:init_it(Starter, Parent, Name, Mod, IArgs, Options).

init_args([Mod, StartArgs]) ->
    [Mod, StartArgs, self];
init_args([Mod, StartArgs, Name]) ->
    [Mod, StartArgs, Name].

That is, the function essentially calls gen_server:init_it/6, since
supervisor_bridge is implemented as a gen_server.

Why do this?

Because I want to be able tell a supervisor to start a generic
server, or other behaviour, and have the supervisor take care of 
actually starting the process. Three immediate advantages come to 

- The supervisor can make sure that the process is started with 
  spawn_link(); Today, if a gen_server is started with e.g. 
  gen_server:start(), supervision will be ineffective (no link.)

- The supervisor is able to execute in the started process before
  handing over control to the behaviour. This way, the supervisor
  can e.g. log information about _why_ the process is started
  (initial start?, restart?, escalated restart?) -- something that
  is not possible today.

- The child start specification becomes more descriptive. Here's
  an example of what it could look like:

  {myServer, gen_server, 
   [{module, myServer},
    {args, []},
    {regname, {local, myServer}}],
   permanent, 2000, worker, [myServer]}

As you might have guessed, I've written such a supervisor.
I will post it shortly.

(As some of you know, we at AXD 301 also specify our permanent
processes in the .app file, and let a central start function take
care of building the supervision hierarchy. The reason for this is 
to make the process structure more visible.)

A still open issue is whether behaviours which do _not_ want a 
process should also be allowed? Actually, we have one already:
application. How would they be defined? Is there a need for 
additional rules?

Comments are welcome.

Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB

More information about the erlang-questions mailing list