A Simplified View of a GenServer
The most famous Actor Model implementation is Erlang Machine, also called BEAM. And OTP is one of the most exciting parts of BEAM. The GenServer is a very flexible and versatile abstraction provided by BEAM. Any server whose design is based on the server/client pattern can be implemented as a GenServer.
A GenServer consists of a mailbox, an event-loop, and a set of callbacks. The runtime concerns are abstracted away. We only need to focus on our solution. Then we pass that to the runtime as a set of callbacks. We are not involved with any concurrency-related concerns!
It sounds stupid to get excited over this. Nevertheless, giant industries rely on this abstraction - and BEAM because it is one of the most interesting cases for the Separation of Concerns principle. It’s like: the GenServer actor (it’s an actor) tells us, “I’ll take care of the runtime concerns (the concurrency stuff), and you take care of the business logic.” And yes, one could argue it is also a case of IoC (Inversion of Control - don’t call us, we’ll call you) - from a runtime point of view.
So the Separation of Concerns principle can be applied not only on the nature-of-the-code axis (the business-specific code, the application-specific code, and the technology-specific code) but also on the runtime axis (async/sync, local/distributed, immutable/mutable state). And the GenServer pattern from OTP does this beautifully.
The best way to recreate the BEAM runtime is to not to. Just use BEAM. But that does not prevent us from exploring!
Here is my take on implementing a GenServer. I called it actor because it can be used as an actor - and I have used it mainly as an actor. We tell the
Start(...) function: “here are our callbacks. Please notify us when we have a new incoming message or when we have to stop”. Then the Start function fires up a new goroutine (the event loop) which reads from the mailbox and triggers the callbacks. We only have to care about the callbacks!
I have used a simple channel for implementing the mailbox. Having concurrency primitives in the API is terrible. But I need to find out what this code might look like and what path it will take if it grows. Also, I wanted to have bounded mailboxes.
Take a look and see how you would improve this - as a coding game, not as an alternative to BEAM. I also have implemented a worker pool using this actor package. Have fun coding!