<div>Hi Richard,</div><div><br></div>Accepted and thanks for taking the time to write the explanation for me (and hopefully it will clarify that question for others too).<div><br></div><div>...so this is more like currying than state. </div><div><br></div><div>Thanks again,</div><div>/s<br><br>On Wednesday, June 27, 2012 7:35:14 AM UTC-5, Richard Carlsson wrote:<blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 06/27/2012 03:15 AM, Steve Davis wrote:
<br>> Is it just me, or is hidden state in a function that appears to the
<br>> client as stateless always bad news... eventually?
<br>
<br>Yes, but this isn't about state. That's what makes it different from 
<br>object oriented programming. Once you create M=mymodule:new(42),
<br>M is always the same M. Nothing that anybody else does can change the 
<br>module instance behind your back. This is just as referentially 
<br>transparent as the following:
<br>
<br>   make_adder(X) -> fun (Y) -> Y+X end.
<br>
<br>   add(A,B) ->
<br>       F = make_adder(B),
<br>       F(A).
<br>
<br>Using parameterized modules, this could be written
<br>
<br>   -module(adder, [X]).
<br>   -export([add/1]).
<br>   add(Y) -> Y+X.
<br>
<br>   -module(foo).
<br>   add(A,B) ->
<br>       Adder=adder:new(B),
<br>       Adder:add(A).
<br>
<br>The main difference between funs and parameterized modules are that 
<br>modules allow you to have several differently named entry points with 
<br>possibly different arities. But you can do that with funs as well if you 
<br>want; it's just more clumsy:
<br>
<br>    make_stepper(C) -> fun ({forward, N})  -> C*N;
<br>                           ({backward, N}) -> -C*N
<br>                       end.
<br>
<br>compare:
<br>
<br>    -module(stepper, [C]).
<br>    -export([forward/1,backward/1]<wbr>).
<br>    forward(N) -> C*N.
<br>    backward(N) -> -C*N.
<br>
<br>Also important is that parameterized modules are by design not tied to a 
<br>particular version of the code (they always call the latest version of 
<br>the module). Funs don't survive reloading the code for the module twice, 
<br>but a module instance can be kept around for a long time.
<br>
<br>A caveat is that (just like funs) existing instances stop working if you 
<br>change the interface and reload the code - for example, changing 
<br>-module(foo, [X]) to -module([X,Y]). That's why I recommend that client 
<br>code should probably never call your_module:new(...) directly, but 
<br>always via some kind of facade, so clients don't know the actual names 
<br>of the modules they instantiate and thus you can update the module name 
<br>along with the interface if you need to to that sort of incompatible 
<br>change: e.g., "make_mod(X) -> mod_v1:new(X)." becomes "make_mod(X,Y) -> 
<br>mod_v2:new(X,Y)."
<br>
<br>     /Richard
<br>______________________________<wbr>_________________
<br>erlang-questions mailing list
<br><a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a>
<br><a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/<wbr>listinfo/erlang-questions</a>
<br></blockquote></div>