Control Flow 1
Last updated
Last updated
Up until now we have seen how to produce some outputs and the various data types. We have also seen how template-structures can be very helpful in calculations and computations like generating the table of a number. However what if we want to output a response depending of the value inside a variable. What if we want to run a part of the code under certain conditions and another part in other situations. This is possible through control flow which we will explore in this section.
Before exploring control flow it is important to understand boolean logic (the mathematics of true
and false
). We have seen in Datatypes 1 that boolean literals can only be of two kinds : true
and false
. There are 3 major operations concerning boolean datatype :
This is the simplest operation concerning booleans. It simply changes true
to false
and vice versa. The action associated with this operation is the not
function. It accepts a single boolean argument and returns its opposite boolean value.
Example : {{$x := true}} {{$y := not $x}}
In this code snippet initially true
is stored in variable $x
. The not
function then performs a not operation in variable $x
(which contains true
) returning false
. Thus eventually false
is stored in $y.
The and
operation is another boolean operation involving two boolean values which results in true
only if both the operands ( values on which it operates) are true
and otherwise results in false
. The following table captures the working of the boolean and
operation.
Operand 1 | Operand 2 | Result |
---|---|---|
You can use the and
function for performing boolean and
operation. It accepts more than two arguments. The evaluated result follows the following logic: Consider three boolean values passed to the and
function. It finds the and
of first and second value. Then it finds the and
of the result from the first two values and the third value. Similar logic applies for more than 3 arguments passed to the and
function.
Example :
{{$x := true}} {{$y := true}} {{$z := false}}
{{$Result := and $x $y $z}}
In the above example, first the and
of variables $x
and $y
results in true
. Then the and
of the result and $z
produces false
. Hence, finally false
is stored in variable Result.
The or
operation similar to and
operation operates on two boolean literals. It results in false
when both the operands are false
and otherwise results in true
. The following table captures the working of the or
operation.
Operand 1 | Operand 2 | Result |
---|---|---|
The or
function is used to perform or
operation. Similar to and
operator, if more than two values are passed to the or
function, if first evaluates the result of the first two operands. Then it performs or
operation on the result from first two operands and the third operand and so on.
Example :
{{$x := false}} {{$y := false}} {{$z := true}}
{{$Result := or $x $y $z}}
In the above example, first the or
of variable $x
and $y
results in false
. Then the or
of the result and $z
produces true
. Hence, finally true
is stored in variable Result.
Having seen boolean operators it is only logical to explore actions that produce boolean values as output. These actions fall under the general category of comparison actions. The following comparison functions are available as a part of standard golang text template package:
eq
: This function checks for equality and returns true
if arg1 == arg2
, that is if both of them are equal. It is worth nothing that for equality to hold both value as well as data type must be same.
ne
: This function is the reverse of the equality function and returns true
if arg1 != arg2
, that is if both of them are unequal, the function returns true
.
gt
: This function returns true
if arg1 > arg2
, that is if first argument is strictly greater than second argument.
ge
: This function returns true
if arg1 >= arg2
, that is if first argument is greater than or equal to second argument.
lt
: This function returns true
if arg1 < arg2
, that is if first argument is strictly less than second argument.
le
: This function returns true
if arg1 <= arg2
, that is if first argument is less than or equal to second argument.
Values of two different data types (eg float64 and int) are not comparable.
Although it is most common to use numerical values in comparison actions, they can compare strings as well. Strings are compared using the Unicode values of their constituent runes(codepoints). If the first codepoints are equal, the second ones are compared and so on.
Only basic data types (int and variants ; float64 and variants and string) can be compared with the comparison actions. The eq
and ne
functions can additionally also compare boolean values.
Equipped with the knowledge of Conditional and Boolean operators and their corresponding actions, we can now explore the very first type of control flow: if-else branching. If else branch statements in their most basic form allows you to execute a certain set of instructions or code if a certain condition is satisfied and a different set of instructions/code if it is the condition is not satisfied. The basic syntax of an if-else action is :
Example :
In the above example first the conditional operator gt checks if the variable $a
contains a number that is more than 0
. Since this condition is satisfied gt returns true
. Since the condition is true, the block of code/statements following the if action is executed. In the above example, Number is more than 0
is printed as output by the bot.
It is important to note here that the else action along with the code to be executed if condition is false (can be referred to as the else block) is not compulsory. However, the {{end}}
statement is compulsory and marks the end of the if-else conditional template-structure.
Example :
In the above example the if block will be executed only if $name
is "YAGPDB"
. Since condition is false
, the if block is skipped and the bot simply prints the output : Hello! Peter
.
While learning the if-else action you must have noticed the term "block". A block is simply a collection of statements or code. With the simple if-else action as an example, the statements following {{if (condition)}}
and before {{else}}
(or {{end}}
if there is no else action) consists of the a single block which can be called the if block. Similarly the statements following {{else}}
and before {{end}}
consists of the else block.
So why are these blocks important anyway? They are important because of an important property of variables called scope. A variable declared in a particular block ceases to exist outside it. This can be illustrated as follows:
{{if eq 1 1}}
{{$a := 1}}
{{end}}
{{$a}}
This code will generate an error because the variable $a was defined inside the if block and ceases to exist after the {{end}}
statement. It is very important to keep a track on a variable's scope while writing codes to avoid such errors.
Defining a variable which already exists makes a local copy of that variable which exists within that block while the outer version is not overwritten and comes back into existence outside the block. This can be avoided by using assignment operator = instead.
Example :
{{$a := 1}}{{$b:= 2}}
{{if eq $b 2}}
{{$a := 3}}{{$b = 5}}{{$a}},{{$b}}
{{end}}
{{$a}},{{$b}}
The above code will Output:
3,5
``
1,5
Earlier we have seen how to execute a block of statements if condition is true and another block if it is false. However if we have multiple conditions in that case the if - else if - else branching is very helpful. This is often called if-else chaining. The general syntax is :
Note : you are not limited to only two else-if blocks but they can be as many as you want. The final else block can also be skipped if not necessary just like the previous case however the {{end}}
statement is necessary to mark the end of the branching action.
Example :
In the above example there are 3 different blocks which are conditionally executed depending on the value of $marks. For the above example, You Passed with distinction
will be printed as output by bot.
Above is an example code which can be used in Join Message. (Note for normal custom commands, bots can't trigger them).
There are two major takeaways from the above example. Firstly notice how an if-else or if-else if-else statement can be used inside another block. In this case it is executed only of the first condition is false for the outer if statement (that is user joining is not a bot). This is called nesting and can be very useful for checking a complex set of conditions. Secondly notice the -
at use in the internal if-else if-else action. It is used to trim spaces to the left and right of the action to aid with formatting. It is discussed in more detail here.
Sample output for normal user joining :
Sample output for bot user joining :
Above snippet will print This message has an attachment
if triggering message has an attachment. Notice how in this example we are using .Message.Attachments which is not of boolean data type as the if statement's condition. This is possible because non boolean variables are automatically converted to boolean when used in a condition according to the following logic :
If the the data represents the empty value [zero value ( nil
, 0
, ""
or false
depending on data type) or empty slices/maps/channels ] of the associated data type, it is evaluated as false
and otherwise as true
. This makes determining if a certain value is nil or empty (or number is zero) very efficient.\
Pro Tip :
Existence of multiple data values can be determined by using the Boolean operators. The logic follows the same logic as for boolean literals after the data values are converted to true
or false
depending on their stored value and datatype.
Example :
{{if or .Message.Attachments .Message.Embeds}}
This is not a simple text message
{{end}}
The above example prints This is not a simple text message
if the triggering message consists any attachments or embeds.
true
true
true
true
false
false
false
true
false
false
false
false
true
true
true
true
false
true
false
true
true
false
false
false