Entry, during and exit actions
Effects that belong to a state rather than a transition: they run when the state is entered, while it stays active, and when it is left, however that happens.
Open a fridge and the light comes on; close it and the light goes off. Why the door opened, or how long it stays open, makes no difference: the light belongs to being open. Until now every effect in your charts has belonged to a transition. This chapter attaches effects to states instead, with entry, during and exit actions, and shows exactly when each one runs.
A fridge light
Section titled “A fridge light”Diagram
Code
scchart Fridge { input bool doorOpen output bool lamp = false
initial state Closed if doorOpen go to Open
state Open { entry do lamp = true exit do lamp = false } if !doorOpen go to Closed}| Tick | input bool doorOpen | output bool lamp | Active state of the chart |
|---|
Guided tour, 5 ticks:
- doorOpen = falseTick 1 enters
Closed. The lamp starts off (lamp = falsefrom its declaration). - doorOpen = trueThe door opens:
ClosedtoOpenfires, and enteringOpenruns its entry action,lamp = true. The transition itself has no effect. doorOpenis still true (inputs keep their value).Openhas nothing to do, solampstays true.- doorOpen = falseThe door closes: leaving
Openruns its exit action,lamp = false. - doorOpen = trueOpen again: the entry action runs again, as it does on every entry.
lamp in ticks 2 and 4: the state Open switches it.The two lines inside Open are its actions:
state Open { entry do lamp = true exit do lamp = false}An entry action runs every time its state is entered. An exit action runs every time its
state is left. They are written inside the state’s braces, after any declarations and before any
inner states, and the diagram lists them under the state’s name as entry / lamp = true and
exit / lamp = false.
With one way into Open and one way out, you could have written do lamp = true on the transition
in and do lamp = false on the transition out. The difference shows as a chart grows. Every new way
into Open would need its own copy of lamp = true, and a forgotten copy is a bug that no compiler
will point out. An entry action says “whenever I am entered” once, in the one place where it belongs.
During actions
Section titled “During actions”A fridge that beeps when its door has been left open needs to count ticks while the door is open. That is the job of a during action: it runs in every tick in which its state is already active.
Diagram
Code
scchart FridgeAlarm { input bool doorOpen output bool lamp = false, beep = false output int openFor = 0
initial state Closed if doorOpen go to Open
state Open { entry do lamp = true; openFor = 0 during do openFor++ exit do lamp = false
initial state Quiet if openFor == 3 go to Beeping
state Beeping { entry do beep = true exit do beep = false } } if !doorOpen go to Closed}| Tick | input bool doorOpen | output bool lamp | output bool beep | output int openFor | Active state of the chart | Active state of the region of Open |
|---|
Guided tour, 8 ticks:
- doorOpen = falseTick 1 enters
Closed. - doorOpen = trueThe door opens. Entering
Openruns its entry action (lamp = true; openFor = 0) and entersQuiet. Theduringaction does not run in this tick:Openwas only just entered. Openwas already active when this tick began, so itsduringaction runs:openForbecomes 1.openForbecomes 2.openForbecomes 3. The during action andQuiet’s trigger run in the same tick, and the update comes first, soopenFor == 3sees 3:QuiettoBeepingfires andBeeping’s entry action setsbeep.- Still open:
openForis 4, and the fridge keeps beeping. - doorOpen = falseThe door closes.
Openis left by ago to, so its during action still runs in this tick (openForis 5). Then the exit actions run from the inside out:Beeping’s (beep = false), thenOpen’s (lamp = false). - In
Closednothing changes:openForkeeps its last value.
openFor counts the ticks after the door opened. Look at tick 2, when it stays 0, and at tick 7, when the door closes and it still goes up.Open is now a superstate with three actions and two inner states. Here is what KIELER’s
simulation shows:
| Tick | doorOpen |
State after | openFor |
lamp |
beep |
|---|---|---|---|---|---|
| 1 | false | Closed | 0 | false | false |
| 2 | true | Open, Quiet | 0 | true | false |
| 3 | true (held) | Open, Quiet | 1 | true | false |
| 4 | true (held) | Open, Quiet | 2 | true | false |
| 5 | true (held) | Open, Beeping | 3 | true | true |
| 6 | true (held) | Open, Beeping | 4 | true | true |
| 7 | false | Closed | 5 | false | false |
Three things are worth a closer look.
The entry tick doesn’t count. In tick 2 the door opens and Open is entered: its entry action
sets openFor = 0, and the during action does nothing. A plain during action is delayed, like a
transition without immediate: it starts in the tick after its state was entered.
A superstate’s during action runs alongside its inner states. In tick 5, openFor++ and the
trigger openFor == 3 of Quiet happen in the same tick, and the trigger sees 3. KIELER treats a
superstate’s during action like one more concurrent region: as with any two regions, the update of
openFor is scheduled before the read of it, whichever comes first in the source. This is the
initialise–update–read order from Concurrent regions.
The tick of leaving does count. In tick 7 the door closes and openFor still goes from 4 to 5.
if !doorOpen go to Closed is a weak abort, and as you saw in Aborts a weak
abort lets the state finish its tick before it is left. The during action is part of that tick.
Then the exit actions run from the inside out: Beeping’s switches the beep off, then Open’s
switches the lamp off.
Including the entry tick
Section titled “Including the entry tick”To run a during action in the entry tick too, write immediate during:
Diagrams
DuringCount
ImmediateDuringCount
Code
DuringCount
scchart DuringCount { input bool start output int n = 0
initial state Idle if start go to Busy
state Busy { during do n++ }}ImmediateDuringCount
scchart ImmediateDuringCount { input bool start output int n = 0
initial state Idle if start go to Busy
state Busy { immediate during do n++ }}| Tick | input bool start | DuringCount: output int n | DuringCount: Active state of the chart | ImmediateDuringCount: output int n | ImmediateDuringCount: Active state of the chart |
|---|
Guided tour, 4 ticks, the same inputs for both charts:
- start = falseTick 1 enters
Idlein both charts. - start = true
IdletoBusyfires in both charts, soBusyis entered in this tick.DuringCount’s plainduringaction skips the entry tick:nstays 0.ImmediateDuringCount’simmediate duringruns in it:nis 1 at once. Busywas active when the tick began, so both during actions run: 1 inDuringCount, 2 inImmediateDuringCount.- One more in each, every tick: the
immediate duringversion stays one ahead.
during (DuringCount) and immediate during (ImmediateDuringCount). Busy is entered in tick 2.| Tick | start |
n with during |
n with immediate during |
|---|---|---|---|
| 1 | false | 0 | 0 |
| 2 | true | 0 | 1 |
| 3 | true (held) | 1 | 2 |
| 4 | true (held) | 2 | 3 |
An immediate during action runs in the entry tick even if the state is left again in that same
tick by an immediate go to. An immediate abort to skips it, as a strong abort skips every during
action in the tick it leaves (more on that below).
What runs, and in what order
Section titled “What runs, and in what order”When a transition is taken, several actions can run in one tick. KIELER always runs them in the same
order. In this chart every action adds 1 to step and records the number it got, so the outputs
show the order:
Diagram
Code
scchart ActionOrder { input bool leave output int step = 0 output int duringAt = 0, exitAt = 0, effectAt = 0, entryAt = 0
initial state A { during do step++; duringAt = step exit do step++; exitAt = step } if leave do step++; effectAt = step go to B
state B { entry do step++; entryAt = step }}| Tick | input bool leave | output int step | output int duringAt | output int exitAt | output int effectAt | output int entryAt | Active state of the chart |
|---|
Guided tour, 4 ticks:
- leave = falseTick 1 enters
A. Itsduringaction waits for the next tick:stepis 0. A’s during action runs:stepis 1, soduringAtis 1.- leave = true
leaveis true. In this one tick:A’s during action (duringAt = 2),A’s exit action (exitAt = 3), the transition’s effect (effectAt = 4) andB’s entry action (entryAt = 5). Each action adds 1 tostepand records what it got. - leave = false
Bhas no transitions and no during action: nothing changes.
leave is true.In tick 3, duringAt is 2, exitAt 3, effectAt 4 and entryAt 5 (step was already 1, from
A’s during action in tick 2). So: A’s during action, then A’s exit action, then the transition’s
effect, then B’s entry action. With superstates, the full rule is:
- If the transition is a weak abort (
go to) or a termination (join to): the source state’s behaviour for this tick, including its during actions. A strong abort (abort to) skips this step. - The exit actions of every state being left, innermost first.
- The transition’s effects, left to right.
- The entry actions of every state being entered, outermost first.
- The immediate behaviour of the target: its immediate transitions and
immediate duringactions.
Each step sees the values that the steps before it wrote. A short way to remember it: leave inside out, enter outside in, and the transition’s effect sits in the middle.
Test yourself on a chart with superstates on both sides. Every action again records the value of
step it produced.
Diagram
Code
scchart NestedOrder { input bool leave output int step = 0 output int innerExitAt = 0, outerExitAt = 0, effectAt = 0 output int outerEntryAt = 0, innerEntryAt = 0, immediateAt = 0
initial state Outer { exit do step++; outerExitAt = step
initial state Inner { exit do step++; innerExitAt = step } } if leave do step++; effectAt = step go to Target
state Target { entry do step++; outerEntryAt = step
initial state First { entry do step++; innerEntryAt = step } immediate do step++; immediateAt = step go to Second
state Second }}In tick 2, leave takes the chart from Outer to Target. Predict the order, then run it.
Inputs per tick. A value in grey was not set in that tick: it holds from an earlier one.
| Tick | leave |
|---|---|
| 1 | false |
| 2 | true |
Explanation
innerExitAt is 1, outerEntryAt 4, innerEntryAt 5 and immediateAt 6. Leaving runs the exit
actions from the inside out (Inner 1, Outer 2), then the transition’s effect (3). Entering runs the
entry actions from the outside in (Target 4, First 5). Last comes the immediate behaviour of the
target: First’s immediate transition (6).
Two more details about order. Several entry actions of one state run in the order they are written, and so do several exit actions. A variable declared inside a state gets its initial value each time the state is entered, just before the state’s entry actions (see Superstates).
Self-loops leave and come back
Section titled “Self-loops leave and come back”A transition from a state to itself is a real exit and a real entry: the exit actions run, then the effect, then the entry actions. For a superstate, the inside starts again from its initial states. That is sometimes what you want, and often not:
Diagrams
SelfLoop
Stay
Code
SelfLoop
scchart SelfLoop { input bool press output int presses = 0, entries = 0
initial state Ready { entry do entries++ } if press do presses++ go to Ready}Stay
scchart Stay { input bool press output int presses = 0, entries = 0
initial state Ready { entry do entries++ during if press do presses++ }}| Tick | input bool press | SelfLoop: output int presses | SelfLoop: output int entries | SelfLoop: Active state of the chart | Stay: output int presses | Stay: output int entries | Stay: Active state of the chart |
|---|
Guided tour, 5 ticks, the same inputs for both charts:
- press = falseTick 1 enters
Readyin both charts and runs its entry action:entriesis 1 on both sides. - press = trueA press.
SelfLoop’s self-loop leavesReadyand enters it again, so its entry action runs again (entries2) and the effect counts the press.Stay’s guarded during action counts the press without leaving:entriesstays 1. - press = falseNo press: nothing changes on either side.
- press = trueSecond press:
pressesis 2 on both sides,entriesis 3 inSelfLoopand still 1 inStay. pressis held, so both count again:pressesis 3.SelfLoophas been entered four times,Stayonce.
SelfLoop a self-loop does it, in Stay a during if press action. Watch entries.| Tick | press |
presses |
entries in SelfLoop |
entries in Stay |
|---|---|---|---|---|
| 1 | false | 0 | 1 | 1 |
| 2 | true | 1 | 2 | 1 |
| 3 | false | 1 | 2 | 1 |
| 4 | true | 2 | 3 | 1 |
| 5 | true (held) | 3 | 4 | 1 |
Both charts count the same presses, but only the self-loop leaves Ready and enters it again each
time. If you mean “do this while staying here”, write a during action with a trigger. If you mean
“start this state over”, a self-loop is right, and its entry actions are part of starting over.
Actions and aborts
Section titled “Actions and aborts”Aborts and actions meet in one question: when a state is cut short, which of its actions still run?
Diagram
Code
scchart Machine { input bool start, stop, emergency output bool motor = false output int ticks = 0
initial state Running { entry do motor = true during do ticks++ exit do motor = false } if emergency abort to Halted if stop go to Halted
state Halted if start go to Running}| Tick | input bool start | input bool stop | input bool emergency | output bool motor | output int ticks | Active state of the chart |
|---|
Guided tour, 7 ticks:
- start = false, stop = false, emergency = falseTick 1 enters
Running: the entry action switches the motor on. The during action waits for the next tick. - Running: the during action counts the tick (
ticksis 1). - stop = true
stopleavesRunningby a weak abort (go to): the during action still runs (ticksis 2), then the exit action switches the motor off. - stop = false, start = true
startentersRunningagain: the motor is on. - start = false
ticksis 3. - emergency = true
emergencyleaves by a strong abort (abort to). The during action is skipped (ticksstays 3), but the exit action still runs: the motor is off. - emergency = falseIn
Halted: nothing changes.
stop in tick 3 is a weak abort, emergency in tick 6 a strong one. Compare ticks and motor in those two ticks.In tick 3, stop leaves Running with go to: the during action still counts the tick (ticks is
2) and the exit action switches the motor off. In tick 6, emergency leaves with abort to: the
during action is skipped (ticks stays 3), but the exit action still runs and the motor is off.
Running is a simple state, and this is the one difference between go to and abort to on a simple
state that Aborts promised.
For a superstate the same holds at every level. Here is the full picture of the tick in which a state is left by a weak abort, a strong abort or a termination:
| In the leaving tick | go to |
abort to |
join to |
|---|---|---|---|
| inner transitions | run | skipped | run |
during actions |
run | skipped | run |
exit actions |
run | run | run |
| effect, then entry actions | run | run | run |
The during row means the state’s own during actions and those of every active state inside it,
and so does the exit row: exit actions run innermost first and the left state’s own last. The first
row and the last column only apply to superstates, which have an inside and can terminate.
So exit actions run however a state is left: by a weak abort, a strong abort, a termination, a
self-loop, or because an enclosing state is left. Think of an exit action as the finally block of
a state; Mode switching relies on exactly that. Entry actions are just as dependable: they run on every entry, even when the state is left
again in the same tick, and even when an immediate abort to fires in the very tick the state is
entered. (Two constructs of Going further are the exceptions: suspend and
deferred entries.) Of the three plain kinds, only during actions depend on how
a state is left.
Conditions on actions
Section titled “Conditions on actions”Every kind of action can have a trigger: entry if c do …, during if c do … and
exit if c do …. What matters is when the trigger is checked. A car’s courtesy light shows it:
Diagram
Code
scchart CourtesyLight { input bool doorOpen, dark output bool light = false
initial state Closed if doorOpen go to Open
state Open { entry if dark do light = true exit do light = false } if !doorOpen go to Closed}| Tick | input bool doorOpen | input bool dark | output bool light | Active state of the chart |
|---|
Guided tour, 7 ticks:
- doorOpen = false, dark = falseTick 1 enters
Closed. - doorOpen = trueThe door opens in daylight. The entry action’s trigger
darkis checked now, at the momentOpenis entered: false, so the light stays off. - dark = trueIt gets dark while the door is open. The entry action has already had its chance: the light stays off.
- doorOpen = falseThe door closes: the exit action runs (the light was off anyway).
- doorOpen = trueThe door opens in the dark:
darkis true at the moment of entry, so the light comes on. - dark = falseDaylight again, but nothing checks
darknow: the light stays on. - doorOpen = falseThe door closes and the exit action switches the light off.
dark changes while the door is open.- An entry trigger is checked once, at the moment the state is entered, after the effect of the
transition that led in. In tick 3 it gets dark while the door is open, and nothing switches the
light on: the entry action has had its chance. In tick 6, the other way round, daylight returns
while the light is on, and nothing checks
darkeither: the light stays on until the door closes. - An exit trigger is checked at the moment the state is left, before the effect of the transition that leaves.
- A during trigger is checked in every tick in which the during action would run.
To switch the light on as soon as it gets dark while the door is open, you would need a during
action, during if dark do light = true, whose trigger is checked in every tick.
Labels
Section titled “Labels”A transition or an action can end with label "…". The diagram then shows the label instead of the
trigger and effects:
Diagram
Code
scchart FridgeLabels { input bool doorOpen output bool lamp = false, beep = false output int openFor = 0
initial state Closed if doorOpen go to Open label "door opens"
state Open { entry do lamp = true; openFor = 0 label "lamp on, start counting" during do openFor++ label "count the ticks" exit do lamp = false label "lamp off"
initial state Quiet if openFor == 3 go to Beeping label "open too long"
state Beeping { entry do beep = true label "start beeping" exit do beep = false label "stop beeping" } } if !doorOpen go to Closed label "door closes"}FridgeAlarm with labels. Switch to the code to see the label clauses; the chart behaves exactly as before.Labels change only the picture, which makes them useful for diagrams that people other than programmers will read. KIELER notes each hidden part with an information message, on actions and transitions alike:
The trigger of this action is hidden by the label.The effects of this action are hidden by the label.A state can have a display name as well, written after its name: state Open "Door open". More on
comments and annotations in Comments and annotations.
Weak and strong actions
Section titled “Weak and strong actions”You may meet four more keywords in other people’s charts. strong entry and strong exit mean the
same as entry and exit. The weak forms are cut short by aborts:
| Written | Runs |
|---|---|
entry, strong entry |
on every entry |
weak entry |
on every entry, except when the state is strongly aborted in its entry tick |
exit, strong exit |
on every exit |
weak exit on a superstate |
only when the superstate terminates through join to; skipped by go to as well as by abort to |
weak exit on a simple state |
on every exit, like exit |
The names suggest “skipped only by strong aborts”, which is not what KIELER does for weak exit. Here
is the same superstate twice, with exit and with weak exit, left once by its join and once by a
plain go to:
Diagrams
PlainExit
WeakExit
Code
PlainExit
scchart PlainExit { input bool finish, cancel output int exits = 0
initial state Task { exit do exits++
initial state Working if finish go to Finished
final state Finished } if cancel go to Idle join to Idle
state Idle go to Task}WeakExit
scchart WeakExit { input bool finish, cancel output int exits = 0
initial state Task { weak exit do exits++
initial state Working if finish go to Finished
final state Finished } if cancel go to Idle join to Idle
state Idle go to Task}| Tick | input bool finish | input bool cancel | PlainExit: output int exits | PlainExit: Active state of the chart | PlainExit: Active state of the region of Task | WeakExit: output int exits | WeakExit: Active state of the chart | WeakExit: Active state of the region of Task |
|---|
Guided tour, 5 ticks, the same inputs for both charts:
- finish = false, cancel = falseTick 1 enters
TaskandWorkingin both charts. - finish = true
finish:Workingmoves to the final stateFinished,Taskterminates, andjoin toleaves it. On a termination both exit actions run:exitsis 1 in both charts. - finish = false
Idle’s delayed transition starts a newTask. - cancel = true
cancelleavesTaskwithgo to, a weak abort.PlainExit’s exit action runs (exitsis 2);WeakExit’sweak exitis skipped andexitsstays 1. - cancel = falseA new
Taskagain. Only a termination runs aweak exiton a superstate.
Note: This weak exit only runs when Task finishes through join to, not when it is left by go to or abort to (WeakExit)
- Note in
WeakExit, line 6, column 5On a superstate, KIELER expands weak exit actions before the aborts, so both kinds of abort bypass them. Use a plain exit action to run something however the state is left.
Task with join to, tick 4 with go to. Watch exits in tick 4.Both exit actions run when Task terminates (tick 2). In tick 4 go to leaves Task: a weak abort,
which lets the during actions and the inner transitions run, but the weak exit is skipped all the
same, and only PlainExit counts. Read weak exit as “on normal completion only”. You will rarely
need either weak form; plain entry and exit are what you want almost always.
Actions of the chart itself
Section titled “Actions of the chart itself”You can also write actions directly inside the scchart braces, after the declarations and before
the first state. They belong to the chart’s invisible outermost state: its entry actions run first in
tick 1, its during actions run in every tick from tick 2 (from tick 1 with immediate), and its exit
actions run when the whole chart terminates.
Try it
Section titled “Try it”One place for the siren
This alarm sets siren = true on two transitions and siren = false on a third. Move the siren
into an entry and an exit action of Ringing, so that no transition mentions it. Then add a
panic input that also starts the alarm from Armed. With the actions in place, the new transition
needs no effect at all.
Show the starter chart
scchart Alarm { input bool door, window, code output bool siren = false
initial state Armed if door do siren = true go to Ringing if window do siren = true go to Ringing
state Ringing if code do siren = false go to Disarmed
state Disarmed if code go to Armed}Show a solution
scchart Alarm { input bool door, window, code, panic output bool siren = false
initial state Armed if door go to Ringing if window go to Ringing if panic go to Ringing
state Ringing { entry do siren = true exit do siren = false } if code go to Disarmed
state Disarmed if code go to Armed}A stopwatch stuck at zero
elapsed should count the ticks since start, but it never leaves 0. Simulate it and work out why
from what you know about self-loops. Then fix it so that elapsed counts while Running is active
and stop still leaves.
Show the starter chart
scchart Stopwatch { input bool start, stop output bool running = false output int elapsed = 0
initial state Stopped if start go to Running
state Running { entry do running = true; elapsed = 0 exit do running = false } if stop go to Stopped do elapsed++ go to Running}Show a solution
scchart Stopwatch { input bool start, stop output bool running = false output int elapsed = 0
initial state Stopped if start go to Running
state Running { entry do running = true; elapsed = 0 during do elapsed++ exit do running = false } if stop go to Stopped}Check your understanding
Section titled “Check your understanding”Show the answer
Answer A: 3 and false
A strong abort skips the state’s during actions in the leaving tick, so onTicks stays 3, but exit
actions run however a state is left, so power is false. With go to Off it would be 4 and false.
Machine above shows both, in ticks 3 and 6.
Show the answer
Answer B: 5
The during action skips tick 2, the entry tick, and runs in ticks 3, 4, 5 and 6. In tick 7 the state
is left by go to, a weak abort, so the during action runs once more before the exit actions: 5.
Show the answer
Answer A: 0: the effect adds 1, then re-entering runs the entry action
Order on a transition: exit actions, then effects, then entry actions. The effect makes elapsed 1,
and the entry action of the re-entered state sets it back to 0. That is the stopwatch bug above.
Key ideas
- An entry action runs every time its state is entered and an exit action every time it is left, whichever transition did it. Put an effect in a state when it belongs to being in that state.
- A
duringaction runs in every tick in which its state is already active: not in the entry tick, but in the tick the state is left bygo to.immediate duringadds the entry tick. - When a transition is taken: the source’s during actions (not for
abort to), exit actions innermost first, the transition’s effects, entry actions outermost first, then the target’s immediate behaviour. - Exit actions run on strong aborts too. Only during actions depend on the kind of abort.
- A self-loop leaves and re-enters its state, so its exit and entry actions run.
- A trigger on an action is checked at that moment; a label changes only the diagram.
Next, The previous tick: comparing a value with its value one tick ago, to react to changes instead of levels.