I was working though a problem and noticed some code where a previous programmer was passing messages using the standard convention of PID ! Message. I have been using gen_server:cast/2. I was wondering if somebody could explain to me the critical differences and considerations when choosing between the two?
2 Answers
There are a few minor differences:
- Obviously, the gen_server handles casts in 
handle_castand "normal" messages inhandle_info. - A cast never fails; it always returns 
ok. Sending a message with!fails withbadargif you are sending a message to an atom that is currently not registered by a process. (Sending a message to a pid never causes an error, even if the process is dead.) - If the gen_server is running on a remote node that is not currently connected to the local node, then 
gen_server:castwill spawn a background process to establish the connection and send the message, and return immediately, while!only returns once the connection is established. (See the code forgen_server:do_send.) 
As for when to choose one or the other, it's mostly a matter of taste.  I'd say that if the message could be thought of as an asynchronous API function for the gen_server, then it should use cast, and have a specific API function in the gen_server callback module.  That is, instead of calling gen_server:cast directly, like this:
gen_server:cast(foo_proc, {some_message, 42})
make a function call:
foo_proc:some_message(42)
and implement that function like the direct cast above. That encapsulates the specific protocol of the gen_server inside its own module.
In my mind, "plain" messages would be used for events, as opposed to API calls.  An example would be monitor messages, {'DOWN', Ref, process, Id, Reason}, and events of a similar kind that might happen in your system.
- 39,593
 - 22
 - 116
 - 167
 
In addition to legoscia post I would say that it is easier to trace dedicated function API than messages. Especially in prod environment.
- 3,578
 - 1
 - 21
 - 23