Lucither wrote:
Is there any reason why the queue above cannot pass the state machine enum instead of a string which is then used to find the enum?
Not inherently. However, passing the state enum directly can impose some limits on the flexibility and clarity of your code. For a completely contrived example, suppose the app has a Save Data button on the UI. Before actually attempting to save the data, we want to make sure the data is valid. How do we implement that?
A common response to this problem is to add a CheckIfDataIsValid state and have the UI send that state instead of the SaveData state. The CheckIfDataIsValid state can then trigger the SaveData state if it confirms the data is valid. This solution certainly works. I don't particularly like it. It tends to lead to state explosion and function machines rather than state machines, which IMO are much more difficult to follow.
A better solution is to create a CheckIfDataIsValid sub vi and put it in the SaveData state, casing out the rest of the save process if there is no data to save. This creates a situation where the SaveData state doesn't always save the data, which can compromise clarity and hinder future extension. What happens if I have situations where I want to save the data regardless of its validity?
My preferred solution is to check if the data is valid before invoking the SaveData state. I'd implement this by sending a "SaveButtonPressed" message to the state loop. The SaveButtonPressed message handling case in the Idle state calls the CheckIfDataIsValid sub vi and invoke the SaveData state only if the data is valid.
Getting back to your question, I could send the SaveData enum and still do the same checking in the message handler before deciding if the SaveData state really should be invoked. I think this just leads to confusion. If the UI is sending a state to the state machine, there is an expectation that the state is invoked. Sending the state directly also couples the UI to the state machine. If I want to give the user an option to save data regardless of its validity I have to create another state, SaveInvalidData. Now I have a SaveData state and a SaveInvalidData state, which essentially do the exact same thing.
The whole point of having a UI loop and a Processing loop is to decouple the UI from the execution. The obvious benefit is that the UI will continue to be responsive while the process is executing. The less obvious (and arguably greater) benefit is the developer can modify the UI and the state machine independently. Using the state enum as the message itself eliminates that benefit.
Granted, a lot of this comes down to personal preference and how you decompose your problem. I generally decompose problems in very modular terms. To me, the state machine is an abstraction of the core functionality of the application--the engine. Each state in the state machine is a public method exposed by the engine. LoadTestConfiguration, SaveData, and ExecuteTest are examples of core functional components. They should be states. CheckIfDataIsValid is the responsibility of the application's supporting code, not the engine, and should not be a state.
Message Edited by Daklu on 04-20-2010 07:34 AM