1

I am new to Erlang, so please go easy on me.

I am confused as to how a receive statement is executed in erlang, for instance:

loop() ->
   receive
       MessageA -> handlerA();
       MessageB -> handlerB()
   end

If a MessageA is received, and handlerA executed, after a while, MessageB is received in the processes' inbox, does handlerB gets executed?

I guess not, since I see a lot of code that recurse to execute the receive statement again:

loop() ->
   receive
       MessageA -> 
          handlerA(),
          loop();
       MessageB -> 
          handlerB(),
          loop()
   end

But here is a problem, if messageA's handler includes another receive statement like this:

loop() ->
   receive
       MessageA -> 
          loop2(),
       MessageB -> 
          handlerB(),
          loop()
   end

 loop2() ->
   receive
      MessageC ->
          handlerC()
          loop2()
      MessageD ->
          handlerD()
          loop2()
   end

In this case, does it mean if I enter MessageA's hander, I can never handle MessageB?

And how can I resolve this? By putting MessageB's handler into loop2? This doesn't look very graceful, especially when there are multiple levels of receive statements.

Is there a better way to do this?

NeoWang
  • 17,361
  • 24
  • 78
  • 126

2 Answers2

4

The following code means "execute receiving a single message", so if you want to receive more than one, you need to loop. The typical way of doing that in Erlang is to tail-call yourself.

loop() ->
   receive
       MessageA -> handlerA();
       MessageB -> handlerB()
   end

In your last example, it looks like you have some sort of state machine, where A changes to another state, whereas B stays in the same state. It is not necessarily a problem that you can no longer receive A messages when you're in the state where you expect C and D messages, but that would depend on the problem domain.

Vatine
  • 20,782
  • 4
  • 54
  • 70
  • Thanks! What if I still expect B message when handling C and D? Do I repeat the handlerB in loop2? This loops very quite verbose. – NeoWang Sep 02 '15 at 09:11
2

You got it.

Concerning your example with loop and loop2, such an implementation means that you want to select some new behavior when you received messageA and you should discard messageB if it comes later. (beware that if you use MessageA with a capital letter it becomes a variable name and it will match any message!). In this case it makes sense, and you should add a garbage message clause to remove from the queue messageB and other unexpected messages:

loop2() ->
   receive
      messageC ->
          handlerC(),
          loop2();
      messageD ->
          handlerD(),
          loop2();
      _ ->
          loop2()
   end.

Another possibility is that you implement a kind of state machine, then you should use the OTP behavior gen_fsm.

If it is not the case, meaning you still want to catch a messageB coming later, I strongly recommend you to keep a single loop and take care of all possible messages in a single receive statement.

Pascal
  • 13,977
  • 2
  • 24
  • 32