Gen_statem receiving data

Hm, not… exactly… (but I may just misunderstand, correct me if so).

Atoms are nice to tag a message to indicate the purpose or type of a message, but they certainly do not make a message unique. In a nutshell, this means that they are not the best fit to (reliably) correlate requests and responses.

For the purpose of tagging requests and the respective replies, you should use references. References are, for all practical reasons, created unique (not strictly, but even if a scheduler thread did create a new reference every nanosecond, they would be reused only after about half a millennium, IIRC).

For example, imagine the following (contrived):

F=fun() -> receive {request, ReplyTo, {A, B}} -> ReplyTo ! {reply, A+B} end end,
P1=spawn(F),
P2=spawn(F),
P1 ! {request, self(), {1, 2}},
P2 ! {request, self(), {3, 4}},
Sum1 = receive {reply, S1} -> S1 end,
Sum2 = receive {reply, S2} -> S2 end.

In the example above, it could be that Sum1 is 3 and Sum2 is 7, but it could just as well turn out the other way round. It is indistinguishable what requests the replies belong to.

It is better done like this (equally contrived):

F=fun() -> receive {request, {ReplyTo, Tag}, {A, B}} -> ReplyTo ! {reply, Tag, A+B} end end,
P1=spawn(F),
P2=spawn(F),
Tag1=make_ref(),
Tag2=make_ref(),
P1 ! {request, {self(), Tag1}, {1, 2}},
P2 ! {request, {self(), Tag2}, {3, 4}},
Sum1 = receive {reply, Tag1, S1} -> S1 end,
Sum2 = receive {reply, Tag2, S2} -> S2 end.

This way, the replies can be correlated to the requests using their Tag* references, so Sum1 is always 3 (reply to the first request), and Sum2 is always 7 (reply to the second request), even if they arrive in reverse order.

Btw, you don’t have to restrict yourself to either atoms or references, you can mix and mingle as needed.

gen:call is a nice example for all the above.

Finally, why do we like to use atoms (vs lists or binaries), here and everywhere else in Erlang? Because atoms are tiny and fast by design (and easily recognizable in code, other than integers would be), just 1 machine word. @garazdawi explained it nicely here. Lists and binaries are much more expensive to throw around.

3 Likes