Quantcast

Design Patterns for Erlang

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Design Patterns for Erlang

Juan A. Suárez Romero
Hi all.

I've been programming with Java during last years, but at present I'm learning
Erlang, and it seems very powerful.

In the development of my Java applications I used the Erich Gamma's
Design Patterns book; but the patterns that appear in it are very based on
inheritance and polymorphism, issues that Erlang hasn't.

Somebody knows where could I find such patterns (or similar patterns) but
applied to Erlang?

Regards,

        J.A.

----------
Dept. of Computer Science
University of A Corunna (Spain)


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Design Patterns for Erlang

Chris Pressey
"Juan A. Su?rez Romero" wrote:
> Hi all.
> I've been programming with Java during last years, but at present I'm learning
> Erlang, and it seems very powerful.
> In the development of my Java applications I used the Erich Gamma's
> Design Patterns book; but the patterns that appear in it are very based on
> inheritance and polymorphism, issues that Erlang hasn't.
> Somebody knows where could I find such patterns (or similar patterns) but
> applied to Erlang?

I'm still a newbie to Erlang, but I've worked "across paradigms" before,
touching on subjects such as patterns and equivalent notions in
different paradigms.  Here is how I see it (which hopefully isn't too
misinformed):

Instead of inheritance, Erlang uses behaviours (functions which take
callback functions, as I understand it.)  In this way a general module
can provide an interface & framework, while specific functionality can
be delegated to another module.  Delegation is a little more general
than inheritance, in that it doesn't denote identity (if A is a subclass
of B, then A is a B; if A is a delegate of B, A is not necessarily a B.)

Polymorphism is a slightly different matter.  Erlang functions are
polymorphic in the sense that they can accept arguments of differing
types, like polymorphic functions in ML.  But this isn't quite the same
as the object-oriented sense.  However, if the crucial aspect of
polymorphism is that a single reference (or name) can refer to more than
one kind of thing, then Erlang supports this, in a way, with dynamic
typing.

Either way, Erlang is not an object-oriented language, so putting either
of these concepts into an Erlang program will require some explicit
coding, although not as much as in a language such as C.

I've wondered if, using structures and funs, one could build a more
classically object-oriented structure into an Erlang program, storing
funs in structure fields and calling them 'virtual methods;' but it
seems like it might be just a waste of time.

I'm pretty sure that delegation and polymorphic functions give the
programmer nearly the same amount of expressive power as inheritance and
polymorphic objects.  I'm not certain that they generate the same
patterns, but (at an educated guess) they are not too dissimilar, that
with some work, they can be applied.

Like I said, I'm still pretty new to Erlang, so I might be wrong in the
above analysis, and if some really experienced Erlang guru contradicts
it, believe them instead!

_chris

--
Change rules.
Share and Enjoy on Cat's Eye Technologies' Electronic Mailing List
http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Design Patterns for Erlang

Lennart Ohman
In reply to this post by Juan A. Suárez Romero
Hi Juan,
at Sj?land & Thyselius Telecom in Stockholm we have done alot of
work on design patterns and also one master thesis regarding
the use of Erlang/OTP and design patterns focusing on simulations.

I will place the report on our web for you to fetch.


Best Regards,
Lennart

"Juan A. Su?rez Romero" wrote:

>
> Hi all.
>
> I've been programming with Java during last years, but at present I'm learning
> Erlang, and it seems very powerful.
>
> In the development of my Java applications I used the Erich Gamma's
> Design Patterns book; but the patterns that appear in it are very based on
> inheritance and polymorphism, issues that Erlang hasn't.
>
> Somebody knows where could I find such patterns (or similar patterns) but
> applied to Erlang?
>
> Regards,
>
>         J.A.
>
> ----------
> Dept. of Computer Science
> University of A Corunna (Spain)

--
-------------------------------------------------------------
Lennart Ohman                   phone   : +46-8-587 623 27
Sjoland & Thyselius Telecom AB  cellular: +46-70-552 6735
Sehlstedtsgatan 6               fax     : +46-8-667 8230
SE-115 28 STOCKHOLM, SWEDEN     email   : lennart.ohman


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Compaq Tru64 UNIX

Vance Shipley-2

Has anyone ever ported Erlang/OTP to Compaq's
Tru64 UNIX running on Alpha processors?

How much grief should I expect?

        -Vance


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Design Patterns for Erlang

Victor M. Gulias-2
In reply to this post by Juan A. Suárez Romero
"Juan A. Su?rez Romero" <centurion> writes:

> Hi all.
>
> I've been programming with Java during last years, but at present I'm learning
> Erlang, and it seems very powerful.
>
> In the development of my Java applications I used the Erich Gamma's
> Design Patterns book; but the patterns that appear in it are very based on
> inheritance and polymorphism, issues that Erlang hasn't.
>
> Somebody knows where could I find such patterns (or similar patterns) but
> applied to Erlang?

First of all, OTP behaviours represent Erlang design patterns as long
as they capture good solutions for common problems. Thus, I recommend
you the 'Design Principles' section on Erlang documentation to learn
about such standard Erlang patterns. In particular, 'gen_server'
behaviour is worth read (both documentation and source code).

In addition, most of GoF patterns (or variants) can also be
implemented using Erlang, even though there is no object-orientation
at all (who need objects? read Joe's comments about OO to understand
what Erlang people think of objects). In the large project that we are
developing at LFCIA, we have identified many problems that could be
solved using, for instance, factory methods, mediators, observers,
chain of responsability, and so on. Of course, in the implementation
you should wisely use the expresiveness of functional programming (who
needs to implement a factory class when you can define anonymous
functions to perform the same task?). In particular, our monitoring
system uses a monitor agent that performs the role of 'Mediator' to
implement a variant of the 'Observer' pattern, separating the actual
processing from visualization.

If this material is interesting for all of you guys, I can write it
down for Erlang PLI workshop or next EUC.

Regards,

--
Victor M. Gulias

PS: Juan, I will include this material in my Ph.D. course on distributed
    functional programming. Of course, you are invited to attend -- just
    go upstairs (office 4.15)


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Design Patterns for Erlang

Richard Carlsson-4
In reply to this post by Juan A. Suárez Romero

On Wed, 14 Feb 2001, Juan A. Su?rez Romero wrote:

> In the development of my Java applications I used the Erich Gamma's
> Design Patterns book; but the patterns that appear in it are very based on
> inheritance and polymorphism, issues that Erlang hasn't.
>
> Somebody knows where could I find such patterns (or similar patterns) but
> applied to Erlang?

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


Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

defining behaviours (Re: Design Patterns for Erlang)

Ulf Wiger-4
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



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Compaq Tru64 UNIX

Kent Boortz-2
In reply to this post by Vance Shipley-2

> Has anyone ever ported Erlang/OTP to Compaq's
> Tru64 UNIX running on Alpha processors?
>
> How much grief should I expect?

I haven't heard of a port to Tru64 Unix. How hard it is depends on
what you mean - a true 64 bit port or running Erlang/OTP as a 32 bit
program on a 64 bit OS.

Back in 1995 I did a 32 bit test port to an AlphaStation 400 running
Digital Unix (formerly OSF/1). If I remember correctly the main part
of the work was to send the right flags to the C compiler and linker,
clean up some non ANSI C code and rewrite small amount of C code. I
may have forgot some problems doing the port but I expect that the
improvements done in the system since makes it easier to do a port.

A true 64 bit port is another story. Major changes has to be done.
The heap and stack sizes will also be doubled if not some sort of
"Erlang process base pointers" are added.

kent

Ref:
   http://tru64unix.compaq.com/faqs/publications/porting/HTML/solaris.html#_Toc414071399
   http://tru64unix.compaq.com/faqs/publications/base_doc/DOCUMENTATION/V51_HTML/ARH9VCTE/PNTRPPXX.HTM


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

defining behaviours (Re: Design Patterns for Erlang)

Mickael Remond-2
In reply to this post by Ulf Wiger-4
On Thu, 15 Feb 2001, Ulf Wiger wrote:

> 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 agree with you. Very interesting indeed.

> 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.

Again I agree. That was one of the first thing that stroke me when reading
this text.

> 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:

You seem to be right. Maybe the OTP people could enlight us on this point, but
it seems to be a good idea.


> (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.)

Making OTP in general more visible is a good thing. OTP is really improving
your application design, especially thanks to behaviour and should be
advertised.

> 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?

Or, maybe we could extend the question ?
Does the application need to be a behaviour or should it be something else ?

Really, I have no answer yet.

--
   Micka?l R?mond                    tel :      (33)1.44.42.00.00
   Project Manager                   mob :      (33)6.60.22.22.16
   15 - 17 avenue de S?gur           e-mail :   mickael.remond
      75007 - Paris                  web :      http://IDEALX.com


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Design Patterns for Erlang

Lennart Ohman
In reply to this post by Richard Carlsson-4
Hi Juan,
this is the report I "spoke" of. It is also available from our web now
at http://www.st.se/telecom/projects

/Lennart

Richard Carlsson wrote:

>
> On Wed, 14 Feb 2001, Juan A. Su?rez Romero wrote:
>
> > In the development of my Java applications I used the Erich Gamma's
> > Design Patterns book; but the patterns that appear in it are very based on
> > inheritance and polymorphism, issues that Erlang hasn't.
> >
> > Somebody knows where could I find such patterns (or similar patterns) but
> > applied to Erlang?
>
> 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
>
> Richard Carlsson (richardc)   (This space intentionally left blank.)
> E-mail: Richard.Carlsson      WWW: http://www.csd.uu.se/~richardc/


-------------------------------------------------------------
Lennart Ohman                   phone   : +46-8-587 623 27
Sjoland & Thyselius Telecom AB  cellular: +46-70-552 6735
Sehlstedtsgatan 6               fax     : +46-8-667 8230
SE-115 28 STOCKHOLM, SWEDEN     email   : lennart.ohman


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

defining behaviours (Re: Design Patterns for Erlang)

Martin Bjorklund-2
In reply to this post by Ulf Wiger-4
Ulf Wiger <etxuwig> wrote:

> 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 wouldn't go that far - of course users can define new behaviours;
you don't have to modify otp_internal.erl at all.  The only function
provided by otp_internal is that the compiler checks exported
functions, and warns if a function required by the behaviour is
missing.  A behaviour is of course much more than this...  This being
said, I think what you propose (the behaviour 'behaviour' :) below
should have been done a long time ago.  (As many other things, it was
a Qn'D hack which seemed fun at the time.)

> 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(_) ->
>   [].

But I think it should be a bit more detailed, specifically we should
make a distiction between mandatory and optional functions:


-module(gen_server).
...
-export([behaviour_info/1]).

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

> 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:

Comments below.

> 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.

What do you mean - the supervisor starts the process already...?

> 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 could call link() explicitly to acheive this effect.
We had endless discussions about this when we implemented this...
It's not safe anyway, since the process could call unlink() when it's
started.  monitor is not a good idea either, since the child wants to
be notified if the supervisor dies.  We agreed that the supervision
mechanism as it is today is for co-operating processes.

> - 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.

On the other hand, today the call-back process is able to execute in
the supervisor before the process is started.  This feature can be
used, and is used, in many interesting ways... ;-)

> A still open issue is whether behaviours which do _not_ want a
> process should also be allowed? Actually, we have one already:
> application.

And gen_event.  They should definitely be allowed!


/martin


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

defining behaviours (Re: Design Patterns for Erlang)

Ulf Wiger-4
On Mon, 19 Feb 2001, Martin Bjorklund wrote:

>Ulf Wiger <etxuwig> wrote:
>
>> 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 wouldn't go that far - of course users can define new behaviours;
>you don't have to modify otp_internal.erl at all.  The only function
>provided by otp_internal is that the compiler checks exported
>functions, and warns if a function required by the behaviour is
>missing. A behaviour is of course much more than this...

Hmm, yes, I'll grant you that. What I meant was that when people
define their own behaviours, they want to be able to enforce these
checks as well... and others. There should perhaps be a good way to
add your own functionality to the linter.


>> behaviour_info(exports) ->
>>   [{init, 1}, {handle_call, 3}, {handle_cast, 2}, {handle_info, 2},
>>    {terminate, 2}, {code_change, 3}];
>> behaviour_info(_) ->
>>   [].
>
>But I think it should be a bit more detailed, specifically we should
>make a distiction between mandatory and optional functions:
>
>
>-module(gen_server).
>...
>-export([behaviour_info/1]).
>
>behaviour_info(mandatory_exports) ->
>  [{init, 1}, {terminate, 2}];
>behaviour_info(optional_exports) ->
>  [{handle_call, 3}, {handle_cast, 2}, {handle_info, 2},
>   {code_change, 3}];
>behaviour_info(_) ->
>  [].


Good idea.


>> 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:
>
>Comments below.
>
>> 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.
>
>What do you mean - the supervisor starts the process already...?


Erm, not exactly. The function that spawns the process does execute in
the supervisor process, but the supervisor has no control over it: it
simply calls an opaque function which (presumably) calls some version
of spawn, and returns a pid.

What I meant was that the supervisor should be given a specification
and _specifically_ start 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 could call link() explicitly to acheive this effect.
>We had endless discussions about this when we implemented this...
>It's not safe anyway, since the process could call unlink() when it's
>started.

Yes, but there's a distinct difference between e.g. calling
gen_server:start() instead of gen_server:start_link() because you
didn't know any better, and explicitly unlinking from the supervisor,
which is really a form of sabotage.

>monitor is not a good idea either, since the child wants to
>be notified if the supervisor dies.  We agreed that the supervision
>mechanism as it is today is for co-operating processes.

I'm thinking that the supervisor needs to use both: monitor in order
to have _guaranteed_ supervision of the child, and link in order to
facilitate cascading EXITs. If the child unlinks from the supervisor,
it might mess up the cascading EXIT, but the supervisor must always be
able to detect a crashed child.


>> - 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.
>
>On the other hand, today the call-back process is able to execute in
>the supervisor before the process is started.  This feature can be
>used, and is used, in many interesting ways... ;-)

Yes, and I've been thinking that it would perhaps be better if the
supervisor was simply given a spec, and we do away with the callback
completely. However, I realise that your smiley refers to my
sysSupervisor callback, which is most likely the most ambitious
supervisor callback yet -- even inventing atoms at runtime. (:
On second thought, we may want to keep the callback module.


>> A still open issue is whether behaviours which do _not_ want a
>> process should also be allowed? Actually, we have one already:
>> application.
>
>And gen_event.  They should definitely be allowed!

Oh yes, I forgot about those. (:


/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



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

defining behaviours (Re: Design Patterns for Erlang)

Martin Bjorklund-2
In reply to this post by Martin Bjorklund-2
A somewhat related issue - the currently internal module 'gen' should
be documented, as it's very helpful when implementing new behaviours
(and also when implementing ordinary erlang processes).  It provides
e.g. a well-tested implementation of
   call(Process, Request [, Timeout]).



/martin


Loading...