Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Having used state machines a lot for embedded development, I find that they have one huge drawback: the resulting C code is unreadable, which turns maintenance into a nightmare.

SM have a key quality: they are a compact and unambiguous way for specifying a behavior. If your system's behavior is set in stone, it's worth specifying it as a SM and implementing it as one. This SM is also great to include in a spec, standard, RFC etc. But if the system evolves, small changes can require dramatic reshaping of the machine.

Also, they can lead to very efficient implementations, especially if you don't have the benefits of a serious OS with a fancy scheduler underneath.



This paper talks about an alternative to SMs:

"Protothreads: Simplifying Event-Driven Programming of Memory-Constrained Embedded Systems" http://www.sics.se/~adam/dunkels06protothreads.pdf

source files (~60 lines without comments): http://www.sics.se/~adam/pt/

abstract:

Event-driven programming is a popular model for writing programs for tiny embedded systems and sensor network nodes. While event-driven programming can keep the memory overhead down, it enforces a state machine programming style which makes many programs difficult to write, main- tain, and debug. We present a novel programming abstraction called protothreads that makes it possible to write eventdriven programs in a thread-like style, with a memory overhead of only two bytes per protothread. We show that protothreads significantly reduce the complexity of a number of widely used programs previously written with event-driven state machines. For the examined programs the majority of the state machines could be entirely removed. In the other cases the number of states and transitions was drastically decreased. With protothreads the number of lines of code was reduced by one third. The execution time overhead of protothreads is on the order of a few processor cycles.


...the resulting C code is unreadable...

It seems to me that, if all of your state machines follow a common pattern, seeing enough of them would make it easier to decipher any given state machine. To a programmer who's never seen an event loop with states represented in a switch block or as function pointers, it may seem unreadable.


Exactly my experience. Over the years we've tried many different ways of coding state machines and it's very hard to keep them readable. Still we continue to use them, the pros outweigh the cons.

There's a pretty interesting RTOS approach based on state machines (www.state-machine.com, no less) that uses single-stack run-to-completion "tasks". They also have some kind of wizard approach to generate code but I haven't had enough time to evaluate it.

For anyone who finds state machines in HLLs unreadable, try looking at a state machine implemented in ladder logic on a PLC!


I am not sure that the accusation of unreadability is valid. The advantage of a state machine is that you can enforce invariants - if you're in state X, then you know categorically that preconditions { X0,X1... Xn} have been met.


Any enum with clear transition logic is effectively a state machine. However, if you try to implement SMs as separate classes/objects with explicit transition functions, than it does become an unreadable mess. The logic in your code stops representing behavior. I think that's what the grandparent post refers to. Also, "explicit" state machines don't allow to use recursion, which can made code much more readable.


the resulting C code is unreadable, which turns maintenance into a nightmare.

I've been doing embedded development for a few years and I love our state machines, they're a pleasure to work with. Maybe yours just sucked.


I feel the same .. all my state machines are lovely. There is nothing quite so rewarding as making an:

    enum { 
        APP_START,
        APP_INIT,
        APP_DO_TASK_A,
        APP_DO ..
        APP_FREE,
        APP_QUIT
    }
.. the center of your applications world! ;)


Amen. I think the only reason state machines are popular in microcontroller work (not really "embedded" -- big SoC software looks like desktop software) is that they're a common hardware implementation choice. And most of those uC programmers are EE cast offs who look to hardware for their reference of taste and not "software engineering".

So they suck in a bad implementation choice because it looks pretty to them. Not so different than the way most Java development works, honestly.


Hoi! I am an EE "cast off" :)

But, yes, you are probably right. When I was taught embedded systems we did do software work, usually on small memory footprints, and state machines were what was taught.


So they suck in a bad implementation choice because it looks pretty to them

An implementation choice that looks pretty is often a good implementation choice.


Except, as I was careful to point out, when it's bad. I hoped my example was useful: people think the OO hell ("class Point", "class Length", ...) in Java is "pretty" too. Aesthetics are squishy. It's easy to point to great code and infer that it's beautiful to other great coders.

But that doesn't change the fact that most people have pretty awful taste. The affinity of uC hackers to state machines, IMHO, is a good example of this.


The readability really depends on your tools. There are state-machines compilers that generate code with e.g. #line directives that hint to the debugger what you want, and even full-fledged IDEs that show the state-transition.

Now if there is a bug in your state-machine compiler, that can be hairy (and it does happen) but the same is true if there is a bug in your C compiler.


Is it really so unreadable? It's not crystal-clear like perfectly linear code as you sometimes have to follow the flow of the state machine through various functions, but syntax-wise once I discovered structs and typedefs, managing state was simple and concise.


What he said. State machines make doing things like figuring out how to from random power loss much, much easier.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: