Live data from Hacker News

State Machines in Rust

blog.yoshuawuyts.com

81–90 of 119 posts

Re: State Machines in Rust

#81
post #60

Noob question but what about state machines where a given state could transition to more than one other state depending on some outside factors? Or is that no longer considered a state machine? For a relevant to me example, a VM state. A VM in running state could be transitioned to terminated or stopped or hibernating depending on an admins action.

that's known as an NFA (Nondeterministic Finite Automaton), a variant of FSMs.

Nondeterminism not needed (or desired I think :D) for an FSM that can turn a VM on or off based on start/stop buttons. Its just multiple possible transitions, guarded by different conditions (the buttons).

But yeah, Nondeterministic FSMs are possible. Ie based on a transition probability.

Re: State Machines in Rust

#82
post #28

For you who enjoying using state machines but wish they did even more and/or were embedded in each other (nested state machines!), check out this thing called State Charts! Here is the initial paper from David Harel: STATECHARTS: A VISUAL FORMALISM FOR COMPLEX SYSTEMS (1987) - https://www.inf.ed.ac.uk/teaching/courses/seoc/2005_2006/res... Website with lots of info and resources: https://statecharts.github.io/ And fi…

Based on the idea of statecharts, we generate a C library that implements a particular complex network protocol: https://github.com/libguestfs/libnbd/tree/master/generator All the files called state* are involved, but the hierarchical state machine is described in this one: https://github.com/libguestfs/libnbd/blob/master/generator/s...

Re: State Machines in Rust

#83
post #28

For you who enjoying using state machines but wish they did even more and/or were embedded in each other (nested state machines!), check out this thing called State Charts! Here is the initial paper from David Harel: STATECHARTS: A VISUAL FORMALISM FOR COMPLEX SYSTEMS (1987) - https://www.inf.ed.ac.uk/teaching/courses/seoc/2005_2006/res... Website with lots of info and resources: https://statecharts.github.io/ And fi…

For more on statecharts, check out Ragel: http://www.colm.net/open-source/ragel/ > Ragel compiles executable finite state machines from regular languages. Ragel targets C, C++ and ASM. Ragel state machines can not only recognize byte sequences as regular expression machines do, but can also execute code at arbitrary points in the recognition of a regular language. Code embedding is done using inline operators that do…

Anyone have a good reference for using Ragel for non-parser tasks? I do a lot of embedded in C and am used to model FSMs for modelling processes, though I still hand-code all of them, which is tedious...

Even invented my own DSL and compiler a while back, but never really had the time to get it good enough to be useful.

Re: State Machines in Rust

#85

In my experience, state machines are very nice in theory, but in practice, over time, they devolve into a mess of spaghetti code. Because they are not in a single scope, loops become the equivalent of a bunch of gotos and managing lifetimes and locks becomes a problem because you can't use scope based mechanisms such as RAII. In Rust, if you want a state machine, generators are probably the long term way to go. https…

State machines really shine in networking protocols where a state machine is part of the spec. I do agree though that when used in applications where it isn’t abundantly clear what the state machine is, or what that state machine is evolving over time that it isn’t the best abstraction.

Re: State Machines in Rust

#86

In my experience, state machines are very nice in theory, but in practice, over time, they devolve into a mess of spaghetti code. Because they are not in a single scope, loops become the equivalent of a bunch of gotos and managing lifetimes and locks becomes a problem because you can't use scope based mechanisms such as RAII. In Rust, if you want a state machine, generators are probably the long term way to go. https…

Resource managing is not a problem with state machines. Quite the opposite: you should acquire/free resources in well defined states of the machine (typically the different entry/exit points).

Generators are great for tasks that fit well but in the general case state machines are more powerful and easier to debug.

I agree that if your state machine starts evolving without control then it will be a mess (like any design).

Re: State Machines in Rust

#87
post #41

Earlier quoted context omitted.

Rust will also support it one day, as part of the const generics feature. Partial support is there behind a feature flag. https://play.rust-lang.org/?version=nightly&mode=debug&editi... #![feature(const_generics)] #[derive(PartialEq, Eq)] // enums used as const generics must be Eq enum Color { Green, Yellow, Red } struct State ; impl State { fn next(self) -> State { State } } impl std::fmt::Debug for State { fn fmt(&…

Are the braces around the const expressions planned to be optional in future? I'm wondering if this will work: impl State { fn next(self) -> State { ... } }

That is the long term plan. In the meantime we also have intentions of making rustc interpret what you want even when the grammar would require the disambiguation so that it can provide the appropriate suggestion in that case.

https://github.com/rust-lang/rust/pull/64700

Re: State Machines in Rust

#88

C++20 supports enums as non-type template parameters, so I think it'd be possible to do it with enums there. Something like: enum class Color{Green, Yellow, Red}; template struct State{}; auto newState() -> State {...}; auto next(State ) -> State {...} auto next(State ) -> State {...} auto next(State ) -> State {...} int main(){ const auto state = newState(); // Green const auto state = next(state); // Yellow const a…

That example does not work, because declaring `state` multiple times creates an illegal C++ program (redeclaration of local variable - notice that this is not the case in Rust). You need to declare variables with different names: const auto state0 = newState(); const auto state1 = next(state0); const auto state2 = next(state1); const auto state3 = next(state); // TYPO -> BOOM use after move I don't think this can be…

> and you can't probably use variant either, since using variant would introduce yet another possible state (e.g. if an exception gets thrown..).

Variants are excellent for a state machine. valueless_by_exception is pretty much irrelevant if your states' relevant constructors and assignments are nothrow.

Re: State Machines in Rust

#89
post #88

Earlier quoted context omitted.

That example does not work, because declaring `state` multiple times creates an illegal C++ program (redeclaration of local variable - notice that this is not the case in Rust). You need to declare variables with different names: const auto state0 = newState(); const auto state1 = next(state0); const auto state2 = next(state1); const auto state3 = next(state); // TYPO -> BOOM use after move I don't think this can be…

> and you can't probably use variant either, since using variant would introduce yet another possible state (e.g. if an exception gets thrown..). Variants are excellent for a state machine. valueless_by_exception is pretty much irrelevant if your states' relevant constructors and assignments are nothrow.

C++ variants are horrible for state machines, since they are not affine types.

Re: State Machines in Rust

#90
post #83

Earlier quoted context omitted.

For more on statecharts, check out Ragel: http://www.colm.net/open-source/ragel/ > Ragel compiles executable finite state machines from regular languages. Ragel targets C, C++ and ASM. Ragel state machines can not only recognize byte sequences as regular expression machines do, but can also execute code at arbitrary points in the recognition of a regular language. Code embedding is done using inline operators that do…

Anyone have a good reference for using Ragel for non-parser tasks? I do a lot of embedded in C and am used to model FSMs for modelling processes, though I still hand-code all of them, which is tedious... Even invented my own DSL and compiler a while back, but never really had the time to get it good enough to be useful.

Source code is closed source and at an old employer, unfortunately, but I once used Ragel to write a non-blocking MySQL client library using the regular expression features for packet parsing and, separately, a state chart for query and session state--basically, which type(s) of packet to expect next and otherwise documenting how session states transitioned.

If I had to do it again[1] I might not use Ragel for either packet parsing or session state. The MySQL wire protocol is rather simple, and Ragel has a steep learning curve, which made hacking on the library unnecessarily difficult for others. At the time I was already knee-deep in Ragel for other stuff, so it was the path of least resistance for me. But for more complex state management I would definitely return to Ragel as the expressive syntax is worth all the documentation and commentary in the world. And because of how well Ragel supports embedded code blocks (including for non-blocking/asynchronous I/O designs), you can maintain proximity between critical code and the state chart directives, which improves both expressiveness and self-documentation. That's the real power of Ragel--it's source code-level interfaces. On the surface the interface seems a little clunky (no interoperability at code AST level), but in practice it's second to none.

[1] Of course, the second time around you already know the pain points and contours of the problem so it's much simpler to open-code an elegant, minimal solution. So it's not much of a comment on Ragel to say that I wouldn't do it again.

Post reply on HN