What Chains Are Running?

What if a property is used in more than just one scenario? How can a property find out in which scenario it's being used?

A typical case: your view model gets data from both user input and database. We want to know which of the chains are active (chain operation context of the view model). We could use a Boolean command property to indicate whether a specific chain is currently running (state of the chain). But how do we clear such a context property without using a setter?

Let's remember the main idea behind PF: "Not an input, then NO(!) set();"
This idea is important because every input (a property with a setter) in our system is a source of uncertainty. If we allow the user ( or a developer ) to set some state variable which has no traits of an input per se (and the abovementioned chain context is a good example of such a property) we make the state uncertain. As a result all the logic relying on this state becomes potentially unstable and non-deterministic.

How to solve this problem? Let's take a look at the following picture.

What's in the picture? Well, the annotation said it's a circuit used to stop and start a motor using push buttons. To many people it says nothing, but there's clearly a message in it. We can use it. Let's examine how it works.
  • Start button completes the chain when pressed,
  • Stop button breaks the chain when pressed,
  • Holding switch is closed when it's connected to a powered circuit, otherwise open.
A button and its switch may be represented in our world as ReloadCommand and Value of a Boolean command property. The motor in our case is a sequence of properties executed in context of our chain. Let's look at the logic of the above circuit.
  • Stop pressed - HS will open,
  • Stop not pressed, Start not pressed - HS will maintain its state,
  • Stop not pressed, Start pressed - HS will close.

Suppose our metaphor makes sense. Let's implement the pattern in the form of a reusable class.

// Implements Start/Stop pattern
public class ChainStarter
{
    public ChainStarter(params Func<bool, IConditionallyReloadable>[] chain)
    {
        _Start = SyncProperty.SyncCommand<bool>(o => !o)
                .TriggersReloadIf((_, c) => c)
                .TriggersReload(_ => _IsRunning, _ => _Start);

        _Stop = SyncProperty.SyncCommand<bool>(o => !o)
                .TriggersReloadIf((_, c) => c)
                .TriggersReload(_ => _IsRunning, _ => _Stop);

        _IsRunning = SyncProperty.SyncCommand<bool>(o =>
            !_Stop.Value && (_Start.Value || o))
                .TriggersReloadIf((p, c) => !p && c)
                .TriggersReload(chain);
    }

    // Start 
    private readonly ISyncCommandProperty<bool> _Start;
    public ISyncCommandProperty<bool> Start { get { return _Start; } }

    // Stop 
    private readonly ISyncCommandProperty<bool> _Stop;
    public ISyncCommandProperty<bool> Stop { get { return _Stop; } }

    // Holding switch
    private readonly ISyncCommandProperty<bool> _IsRunning;
    public ISyncCommandProperty<bool> IsRunning { get { return _IsRunning; } }
}
The above code implements our desired logic. Let's elaborate on the logic. The desirable logic of the system is in the table below.

HS Start Stop HS new
False False False False
False False True False
False True False True + Start M
False True True False
True False False True
True False True False
True True False True
True True True False

Hence the formula used in the above code to calculate HS new = !Stop && ( Start || HS ). It literally means that HS will be closed only if Stop isn't pressed and either it is closed or Start is pressed. The motor will certainly be started only when HS is changed from False to True.

Answering the original question: we just check MyChainHoldingSwitch.Value, if True then then we are in the chain_.

Besides, consider how electric diagrams are declarative and not imperative! Arguably, declarative is less verbose and thus more reliable then imperative. Electric diagrams also tend to feature composition. We can compose a virtually unlimited number of appliances from a very limited number of components. Probably, you happened to find some other similarities.

In electrical circuits we deal with currents, in C# we deal with execution flow. In case of business logic, however, just for now we don't need to model real electric processes. We use them as a metaphor and therefore omit their analogue traits. Perhaps, one day we'll need to take these features into account too.



This pattern is used in the Load-By-Wire Pattern. Invent it yourself or find out NOW how the idea of an autopilot can help us build bullet-proof input forms.

Last edited Jul 2, 2013 at 6:21 PM by Vitaly_Kamiansky, version 9

Comments

No comments yet.