otp
otp copied to clipboard
[feat] an equivalent for `gen_statem`
Hi,
The gen_statem behaviour provides a powerful way to manage stateful processes, especially for development of complex state machines and stateful systems.
It would be great to see something similar for Gleam.
Could you go into more detail as the specific requirements for this new process abstraction, including the sorts of problems you would solve using it, and what a typed API might look like? Thank you.
Requirements
I don't think it should be actually same with gen_statem, but should be a module that simplifies the process of creating FSMs in Gleam, making FSM implementation more accessible and straightforward for most of the case.
Use Cases
Many services, like chat servers and database connections involve maintaining state across multiple interactions. The new equivalent can provide a clean way to manage such states. It can be also used to manage resources like database connections and network sockets for ensuring proper initialization, use, and cleanup.
Implementation
I'm currently considering an approach based on the actor module to seamlessly integrate the new abstraction within the existing hierarchy. To explore this idea further, I plan to develop a prototype library that demonstrates how something similar to gen_statem can be implemented in Gleam.
Given Gleam is a typed language how could a library create a finite state machine? They are typically created using types, which the programmer defines.
Assuming there's a good design for a library creating FSMs, why would it be part of gleam_otp rather than a stand alone package that isn't coupled to a particular concurrency abstraction?
Given Gleam is a typed language how could a library create a finite state machine? They are typically created using types, which the programmer defines.
I don't think that being a typed language is an issue here, as there are already libraries available for typed languages. Checking their implementations may assist us in developing one for Gleam.
Assuming there's a good design for a library creating FSMs, why would it be part of gleam_otp rather than a stand alone package that isn't coupled to a particular concurrency abstraction?
You are correct; I had considered this repository because it's within Erlang/OTP. Maybe leaving this to the community might be a better choice...
Could you share some of those libraries? I was unable to find any for well typed languages without macros, and the ways I know of making FSMs don't have anything that be extracted in to a library.
I've come across several state machine libraries:
I'm not entirely certain if these libraries employ any behind-the-scenes magic. Particularly, the ZigFSM appears quite clean and straightforward.
Maybe we can also consider the Elm architecture, as it resembles me a state machine.
Sorry, to be clear I mean languages with very robust type systems like Gleam, so OCaml, Elm, Rust, etc.
Go, Zig, and C# are statically typed, but their type systems are much less strict then Gleam's, so they're not very useful references as what works in them tends not to work with a stronger type system.
edit: Looking more at those libraries I think they're largely replicating Gleam's case expressions, so in a Gleam program we could have a similar experience without any library boilerplate, just using the language itself.
It's my fault since I'm not entirely sure how the type system works in Gleam. I used to believe that functions in Gleam could optionally have their argument and return types annotated, which would somehow enable library users to use their own Event and Message types.
However, I'm currently feeling confused about this. 😅
I think a good way to approach this would be to implement some of these protocols and see what sort of code arises when doing it in Gleam. Once we've done a few iterations of this we can figure out if there's any abstractions that can be lifted out of those production tested solutions. Trying to make a solution without specific problems often results in a weaker solution in my opinion.
Just sharing a nice example of using gen_statem in Elixir: https://andrealeopardi.com/posts/connection-managers-with-gen-statem