tags:

views:

107

answers:

3

When should I use process-wide dictionary and when should my process state be in the parameters of the loop function?

This:

loop() ->
  receive
     {From, subscribe} ->
       put(listeners, [From|get(listeners)]),
       ?MODULE:loop()
  end.

Or this:

loop(Listeners) ->
  receive
    {From, subscribe} ->
       ?MODULE:loop([From|Listeners])
  end.

?

Parameters to the loop function has the benefit of being explicit in that nothing outside it can change the parameters (unless you're doing strange magic bouncing on another function like a trampoline), but state tends to add up, and the parameters with them.

How about a dict as a parameter? Best of both worlds or worst of both worlds?

+2  A: 

The main disadvantage of using the process dictionary relates to the possible side-effects: when you start using the process dictionary liberally, you'll have more difficulty tracking possible side-effects.

For example, let's say you are in function "X" and start pulling data from the process dictionary, then you are effectively working against the functional nature of Erlang.

But hey, at some point you'll need to have access to a bigger data store, won't you? The point is: try to isolate as much as possible access to the process dictionary.

jldupont
Speaking of functional nature... is pulling messages from the mailbox (i.e. receive) any different from pulling data from the process dictionary, in terms of functionality?
Zed
well, if you are pulling messages right-left-and-center from the mailbox in your code, I would argue it is a bad idea. I guess your comment might be related to the fact that the question was centered around (possibly) the main message loop of the application. I was being more generic.
jldupont
Another point to bear in mind is that function parameters work correctly in the presence of exceptions but values in the process dictionary aren't restored - so either don't mix exception handling and the process dictionary, or better yet, avoid the process dictionary.
archaelus
+6  A: 

I would suggest you to use a record to store your loop data. That way if you ever need to add a new "variable" to your loop data all you have to do is add it to the record, without touching any of your clauses. Dict would only be a better choice if your "keys" recently change, which is unlikely in the case of loop data.

-record(state, {
           listeners = [],
           new_var   = undefined,
           new_var2  = ""
           ...
        }).

init() ->
  loop(#state{}).

loop(State) ->
  receive
    {From, subscribe} ->
       loop(State#state{listeners = [From|State#state.listeners]});
    somethingelse ->
       do_nothing(),
       loop(State)
  end.
Zed
+1  A: 

Another big disadvantage to using the process dictionary is that it becomes a lot harder to do tracing when the data you have is not passed in through the function call.

Lukas
That's what I meant by "benefit of being explicit in that nothing outside it can change the parameters". I was looking for the alternative when the state grows and grows. Records would fit that niftily.
Thomas