I use both methods for FSMs, but when reading someone else's code almost always I find it easier to follow if it's a case statement rather than a function pointer, it's right there in your face. I use "clever" things like function pointers less and less as I get older, not because I'm going senile particularly (!) but because I know when I go back to look at even my own code several months down the line stuff like this sometimes unnecessarily gets in the way of comprehending quickly what is happening.
As I said, I've seen undisciplined use of if-the-else statements in complex FSMs "blossom" into unmaintainable cancers
And no, those statements weren't autogenerated from a higher level description.
As for re-comprehending, if the design pattern is remembered and suitable names are given, then I've found it easy to pick up. Of course if those aren't followed, all bets are off!
My concern is usually around whether some piece of language functionality is used to show off one's chops because at the time you might think it's more elegant rather than whether it's easily maintainable. If you have to spend time reverse engineering your own or someone else's algorithms and data structures, rather than following simple program flow, then for me at any rate the simple in your face version wins. That is not to say there's a time and a place though!
Completely agree, but I'll add some constraints for what consititues "maintainable"
for FSMs. When an event occurs in a state, I want to be able to
- determine which piece of code gets executed
- change what happens, in the knowledge that I haven't affected any other state/event's action
- log the state/event for debugging and for live-system audit trails
The latter is
invaluable when a problem occurs and you need to demonstrate the problem is with other manufacturer's equipment.
Having said all that, the concept of function pointers is inherently locked up inside polymorphism in OO languages like C++, it's just that as humans we choose not to see them as function pointers.
The standard OO FSM design pattern is extremely useful since, with some boilerplate it enables all the valuable attributes I've previously mentioned.