[erlang-questions] Parameterized module initialization

Richard Carlsson carlsson.richard@REDACTED
Wed Jun 27 14:35:14 CEST 2012


On 06/27/2012 03:15 AM, Steve Davis wrote:
> Is it just me, or is hidden state in a function that appears to the
> client as stateless always bad news... eventually?

Yes, but this isn't about state. That's what makes it different from 
object oriented programming. Once you create M=mymodule:new(42),
M is always the same M. Nothing that anybody else does can change the 
module instance behind your back. This is just as referentially 
transparent as the following:

   make_adder(X) -> fun (Y) -> Y+X end.

   add(A,B) ->
       F = make_adder(B),
       F(A).

Using parameterized modules, this could be written

   -module(adder, [X]).
   -export([add/1]).
   add(Y) -> Y+X.

   -module(foo).
   add(A,B) ->
       Adder=adder:new(B),
       Adder:add(A).

The main difference between funs and parameterized modules are that 
modules allow you to have several differently named entry points with 
possibly different arities. But you can do that with funs as well if you 
want; it's just more clumsy:

    make_stepper(C) -> fun ({forward, N})  -> C*N;
                           ({backward, N}) -> -C*N
                       end.

compare:

    -module(stepper, [C]).
    -export([forward/1,backward/1]).
    forward(N) -> C*N.
    backward(N) -> -C*N.

Also important is that parameterized modules are by design not tied to a 
particular version of the code (they always call the latest version of 
the module). Funs don't survive reloading the code for the module twice, 
but a module instance can be kept around for a long time.

A caveat is that (just like funs) existing instances stop working if you 
change the interface and reload the code - for example, changing 
-module(foo, [X]) to -module([X,Y]). That's why I recommend that client 
code should probably never call your_module:new(...) directly, but 
always via some kind of facade, so clients don't know the actual names 
of the modules they instantiate and thus you can update the module name 
along with the interface if you need to to that sort of incompatible 
change: e.g., "make_mod(X) -> mod_v1:new(X)." becomes "make_mod(X,Y) -> 
mod_v2:new(X,Y)."

     /Richard



More information about the erlang-questions mailing list