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:
>
> ftp://ftp.csd.uu.se/pub/papers/masters-theses/0178-ekstrom.pdf
>
>
> /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
behaviour.
- In each behaviour, export a function B:behaviour_info(Category),
for example like this:
-module(gen_server).
...
-export([behaviour_info/1]).
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
this:
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
mind:
- 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.
/Uffe
--
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