Untangling the Signal Slot Spaghetti with SCXML

Jump to the Qt-SCXML lab

Signals and slots have been, since the dawn of Qt, a great way to avoid spaghetti code. You can decouple the elements of the program, and have the inputs from one element and the outputs of another be connected externally with QObject::connect(...).

However, this is not always enough. Many times, when I write Qt applications, I find myself having to define a set of rules between one element's signal and another element's slot, based on state and some conditions.
I end up adding an intermediate slot, 'if' and 'switch' statements, and end up with more spaghetti code. This spaghetti code can arguably be referred to as an "implicit state machine" - a set of rules based on state, that doesn't look like a designed state machine.

Concurrency


There are two aspects to concurrency. When I cook spaghetti with meatballs, I can put the spaghetti on one burner, and the meatballs on the other burner, and they'll cook concurrently. That's equivalent to threading and QtConcurrent. The other aspect is managing my own concurrency. I have to react to the water boiling by adding salt and olive oil, react to the water boiling again by adding the pasta, react to the meatballs being ready by getting them off the stove, and react to the fire started in the kitchen by calling 911. In essence, I cook the spaghetti and meatballs "concurrently" even though I perform one task at a time. That aspect is equivalent to a finite state machine.

Coding spaghetti


The spaghetti header file with C++, Qt, and signals/slots:

Spaghetti h file


If I want to implement my spaghetti boiling mechanism in C++, I would need an intermediate function, something like this:

Spaghetti Function


This if statement is the essence of spaghetti code. I have to route the water-boiling signal through this intermediate function and end up with endless functions and if/switch statements just to implement these implicit state machines.I have to admit that I find myself writing such code pretty often. Debugging and scaling this code is like separating the spaghetti noodles from each other, one at a time (luckily in this example there are only two noodles.)With state machines, I don't need this intermediate function. Instead, I implement the "raw" signals and slots, and author the rules/logic in SCXML:

Spaghetti Boiling SCXML

Note how I can connect to the same signal twice, and have it perform two completely different actions. And I can do that in a managed and readable way.

Real world examples


If you had it with spaghetti, here are some real world implementations you can do with Qt and SCXML.

Non-modal Dialogs

Modality comes from the imperative nature of languages like C++. It does not exist in nature. Imagine if your car would ask you "Are you Sure?" every time you stepped on the break pedal. When managing states correctly with a state machine, we don't need modal dialogs. Run the blackjack example, press "Exit" and then "New Game" to see how a smoother UI can be achieved without modality.

Go Back

Many programs have a browser-like "Back" button. This is, however, not always easy to implement. The app has to maintain a stack of states and it needs to be able to restore each of these states. SCXML handles that with the "anchor" module. See the multimedia example for a use of anchors to achieve back-button functionality.

Internet Radio

An internet radio apps receives real-time events from 3 sources: user requests, network responses, and media-engine state changes. Handling the rules of execution and cleanup for such application can become quite complex, and formalizing it in a state-chart makes life a lot easier. This is true for every "reactive" system, a system that receives user and/or system events and has to react to them based on rules.

UI is not just graphics


I upload my music library to my new media-playing device. When I try to play my favorite Pink-Floyd album, I find out that all the songs are duplicated. Slightly irritated, I go to the first duplicated song and choose the "delete" function. After 2 seconds of nothing, I get a modal progress bar indicating that the song is being deleted. After about 20 seconds, I'm back at the menu and can play the song again.So, I had a terrible user experience, and it had nothing to do with flashy graphics. If the states of that applications were managed robustly, and I could continue browsing my song list as the track was being deleted from the disk, I could end up enjoying this device a lot more.

Duplication with the animation-framework states?


People might say this resembles the state XML in the animation framework. The two features do indeed handle "states" but with very different use cases in mind - the animation framework handles GUI states and animated transitions between them, while SCXML is a general purpose "powerhouse" state machine, and can be used without GUI at all. The programming examples above, for example, cannot be achieved easily with the animation states, while animation is harder to achieve with SCXML.

A Project Manager's Dream


Sometimes projects managers (or other middle-managers) have little or no coding skills. Yet, they want to be able to control and understand the architecture of their product, without taking the coder's word for it. SCXML provides a clear representation of flow requirements, and since it doesn't "generate" code, the project manager can look at it and see why the application behaves the way it does, and even make minor changes without the fear of "breaking something".
More info on the SCXML lab page.

Bon Appetit!

Blog Topics:

Comments