Flow control
Flow control is an essential tool in all programming languages and Colang supports this as well. It enables branching and repetition of interaction patterns in a single flow.
Conditional Branching (if/elif/else
)
Important
Syntax definition of conditional branching:
if <condition1>
<interaction pattern sequence 1>
[elif <condition2>
<interaction pattern sequence 2>]
.
.
.
[else
<interaction pattern else sequence>]
The conditional branching is a well known concept and works identical to Python:
flow main
$number_of_users = 1
if $number_of_users == 0
await user became present
elif $number_of_users > 1
bot say "I am sorry, I can only interact with a single user!"
else
bot say "Welcome! Nice to meet you!"
match RestartEvent()
In this example the bot’s reaction depends on the state of the variable $number_of_users
that would contain the number of available users.
Event Branching (when/or when/else
)
Event branching is a new Colang based concept that enables a branching based on expected events.
Important
Syntax definition of event based branching:
when <MixedGroup1>
<interaction pattern sequence 1>
[or when <MixedGroup2>
<interaction pattern sequence 2>]
.
.
.
[else
<interaction pattern else sequence>]
The <MixedGroup> stands for a mixed grouping of flows, actions and events
All actions and flows in the
when/or when
statements will be started concurrentlyIf neither the
or when
nor theelse
statement is used, thewhen
construct could be replace with either just anawait
ormatch
statement
With the concurrent pattern matching mechanism we have already seen one way to design a branching interaction pattern based on the users input:
flow main
bot say "How are you?"
bot react to user feeling good or bot react to user feeling bad
flow bot react to user feeling good
user said "Good" or user said "Great"
bot say "Great"
flow bot react to user feeling bad
user said "Bad" or user said "Terrible"
bot say "Sorry to hear"
Depending on the user’s answer we will get a different bot reaction. Although this concurrent flow mechanism is very powerful, it is sometimes better to have everything in a single flow with the help of the when
construct:
flow main
bot say "How are you?"
bot react to user wellbeing
flow bot react to user wellbeing
when user said "Good" or user said "Great"
bot say "Great"
or when user said "Bad" or user said "Terrible"
bot say "Sorry to hear"
The number of cases can easily be extended by adding more or when
statements. The else
statement will only trigger if all of the when/or when
statements have failed.
From the definition we see that when/or when
statements support mixed groups that can contain events, actions and flows. For events this works like a match
statement, whereas for actions and flows it behaves like an await
statement. Therefore, actions and flows will be started and then matched with their Finished
event. Note, that all flows and actions will be started concurrently in the different when/or when
statements and stopped as soon as the first case succeeds.
Important
All started flows and actions in all the when/or when
statements will be stopped as soon as one of the cases succeeded.
We can also use this construct to easily create a branching for a flow that either finishes or fails:
flow main
start pattern a
when pattern b
bot say "Pattern b has finished"
else
bot say "Pattern b has failed"
flow pattern a
user said "Hello"
bot say "Hello"
flow pattern b
user said something
bot say "Hi"
Due to the event generation conflict resolution ‘pattern b’ will fail for the user input “Hello”, but successfully finish for the user input “Hi”:
> Hello
Hello
Pattern b has failed
> Hi
Hi
Pattern b has finished
It is considered “bad design” when used with action-like flows that start with an action:
flow bot greet then comment
when bot say "Hi there!"
bot say "I am done talking first"
or when bot gesture "Wave with one hand"
bot say "I am done gesturing first"
flow bot say $text
await UtteranceBotAction(script=$text)
flow bot gesture $gesture
await GestureBotAction(gesture=$gesture)
This example will not work correctly because only one of the two actions will be started due to the action conflict between UtteranceBotAction
and GestureBotAction
. Note, that such cases can be easily detected when following a proper flow naming convention since when bot say "Hi there!"
is grammatically incorrect. The example above would need to be implemented like this:
flow bot greet then comment
start bot say "Hi there!" as $action_1_ref
and bot gesture "Wave with one hand" as $action_2_ref
when $action_1_ref.Finished()
bot say "I am done talking first"
or when $action_2_ref.Finished()
bot say "I am done gesturing first"
Important
The when/or when/else
branching should only be used with intent-like flows.
Loop (while
)
Important
Syntax definition of a loop:
while <condition>
<interaction pattern sequence>
In this example the bot will count from one to ten:
flow main
bot count to 10
flow bot count to $number
$current_number = 1
while $current_number < $number
bot say "{$current_number}"
$current_number = $current_number + 1
In order to abort the loop early or to skip the rest of the current loop iteration the keywords break
and continue
can be used, respectively:
flow bot count to $number
$current_number = 0 # Initialized it with 0
while True # Endless loop
bot say "{$current_number}"
$current_number = $current_number + 1
if $current_number == 0
continue # Skip the number 0
if $current_number > $number
break # Break out of loop when target number was reached
Finish or abort a flow (return/abort
)
Flows can be finished or failed at any point from within the flow using the keywords return
and abort
, respectively:
flow main
user greeted then expressed feeling unwell
flow user greeted then expressed feeling unwell
match user greeted
when user expressed feeling unwell
return
or when user said something
abort
# We never reach this, except if both cases fail
Additionally, return
takes an optional value such that you can use a flow like a common function:
flow main
$result = await multiply 3 4
bot say "{$result}"
flow multiply $number_1 $number_2
return $number_1 * $number_2
If no return value is provided you None
is passed by default.
Note
When assigning the return value of a flow to a variable await
is not optional before the flow name.
No-op operation (pass
)
Sometimes, it is useful to have a no-operation keyword pass
, e.g. as placeholder to make e.g. the syntax valid:
flow main
user greeted then expressed feeling unwell
flow user greeted then expressed feeling unwell
match user greeted
when user expressed feeling unwell
pass # Just continue with the flow
or when user said something
abort
# The flow will successfully finish here