To (Gen)Serve or not to (Gen)Serve

facilis descensus Averno
the descent to Avernus [the underworld] is easy : the road to evil is smooth
Virgil, Aeneis, Book VI, 126.

or more plainly “convenience can be the root of all sorts of evils”.

https://twitter.com/jessitron/status/333228687208112128?lang=en

Kernel.spawn/3, Kernel.send/2 and Kernel.receive/1 are called concurrency primitives - i.e. they were created to enable and support multiple, independent flows of execution - the end game wasn’t to furnish the building blocks for a container of mutable state inside an immutable environment.

Now both Agents and GenServers use recursion to maintain state - but that shouldn’t be mistaken as a license to go on a mutable state rampage à la OO (actually Agents get mixed reviews - easy to learn but not all that useful).

Mutable state is necessary to “get stuff done” but it is also useful to minimize the reliance on mutable state - even when it is inconvenient - in order to keep things “easy to reason about”. In the Clojure community you often come across the notion that good (immutable) functional design “pushes the (impure aspects) to the edges of the system” - that type of design should still be a desirable goal with BEAM languages.

Coming from OO it’s very tempting to look for “object equivalents” but in FP it’s all about data transformation; processes are essentially services.