Textual StatechartsThe one thing I would like to note first, though it'll probably be pretty obvious, is the notation I've adopted for writing UML states without diagrams. It's straightforward enough, but just to document once by example, here's Samek's toaster oven chart ( original posted below ) rendered as text:
I think this is pretty easy to read even without knowing a thing about statecharts, but it more or less follows the UML syntax. And it's also vaguely YAML-like...
Heating: - enter /start_heater(); - exit /stop_heater(); - init >> Toasting. - toast >> Toasting. - bake >> Baking. - open >> Open. Toasting: - enter /arm_timer(); - exit /disarm_timer(); - do [timer elapsed] / eject_toast(); Baking: - enter/set_temp(); - exit /set_temp(); Open: - enter /illuminate(); - exit /extinguish(); - close >> Heating.
State names appear first. The outermost initial state appears at the top, and child states are listed "within" their parent state. Other than that the order of states doesn't matter much. In this case ( presumably after you turn the darn toaster oven on ) the first state is "Heating".
Listed underneath each state are all of the events that affect it, preceded by a dash. The UML reserved labels ( enter, exit, do, include ) appear first ( if they needed). Also, just as in UML, a single forward slash precedes any action that might occur in response to an event. "Heating: enter/start_heater();" indicates that when heating starts, the machine should start the heater.
The "init event" may require some explanation, but basically, in a UML statechart, you must always move to as leaf a state as possible. Heating, here, has two child states, so you can't just be heating: you must also *either* be toasting or baking. This formalism allows you to share what's common in the parent state with what's unique in each child state. The "init" simply says which one you move into by default. In UML, however, there is no such "init" event. Instead, the default flow is represented with an "initial pseudostate" ( a solid black circle, and arrow. ). Functionally, however, it means the same thing.
Custom events follow the predefined events. "toast" refers to when someone flips the toast switch, "bake" when someone flips the "bake" switch, "open" when they open the toaster door.
The C++ right-shift operator >> indicates the movement from one state to a next. "Heating: init >>Toasting." means the first default child state for Heating is Toasting. "Heating: open>>Open." means if someone opens the toaster's door, move into the "Open" state. All, pretty straight forward.
After the custom events come substates, indented one or more spaces. As you've probably already gathered, state declarations are followed by colons ( eg. "Heating:" ), similar to YAML's associative array of lists, while references to states are terminated with periods.
Finally, any guard conditions that must be met for an event to be processed are in square brackets. In the above example, the reserved event "do" gets polled at a system defined rate, very much like Flash's enter frame event. The guard I added to Samek's chart evaluates whether the timer setup by the Toasting:enter action has finished, and if so, it ejects the toast.
Here's Samek's original statechart:
|UML statechart by Miro Samek, licensed under Creative Commons 3.0 Share-Alike|
I will get to regions eventually, though there are none in this example. They will use triple dash (---) separation similar to the "new document" separation that YAML uses.