Control Flow
Control flow statements control the flow of execution in a function.
Conditional branching: if-statement​
If-statements allow a certain piece of code to be executed only when a given condition is true.
The if-statement starts with the if
keyword, followed by the condition,
and the code that should be executed if the condition is true
inside opening and closing braces.
The condition expression must be boolean.
The braces are required and not optional.
Parentheses around the condition are optional.
_13let a = 0_13var b = 0_13_13if a == 0 {_13 b = 1_13}_13_13// Parentheses can be used around the condition, but are not required._13if (a != 0) {_13 b = 2_13}_13_13// `b` is `1`
An additional, optional else-clause can be added to execute another piece of code
when the condition is false.
The else-clause is introduced by the else
keyword followed by braces
that contain the code that should be executed.
_10let a = 0_10var b = 0_10_10if a == 1 {_10 b = 1_10} else {_10 b = 2_10}_10_10// `b` is `2`
The else-clause can contain another if-statement, i.e., if-statements can be chained together. In this case the braces can be omitted.
_22let a = 0_22var b = 0_22_22if a == 1 {_22 b = 1_22} else if a == 2 {_22 b = 2_22} else {_22 b = 3_22}_22_22// `b` is `3`_22_22if a == 1 {_22 b = 1_22} else {_22 if a == 0 {_22 b = 2_22 }_22}_22_22// `b` is `2`
Optional Binding​
Optional binding allows getting the value inside an optional. It is a variant of the if-statement.
If the optional contains a value, the first branch is executed and a temporary constant or variable is declared and set to the value contained in the optional; otherwise, the else branch (if any) is executed.
Optional bindings are declared using the if
keyword like an if-statement,
but instead of the boolean test value, it is followed by the let
or var
keywords,
to either introduce a constant or variable, followed by a name,
the equal sign (=
), and the optional value.
_10let maybeNumber: Int? = 1_10_10if let number = maybeNumber {_10 // This branch is executed as `maybeNumber` is not `nil`._10 // The constant `number` is `1` and has type `Int`._10} else {_10 // This branch is *not* executed as `maybeNumber` is not `nil`_10}
_10let noNumber: Int? = nil_10_10if let number = noNumber {_10 // This branch is *not* executed as `noNumber` is `nil`._10} else {_10 // This branch is executed as `noNumber` is `nil`._10 // The constant `number` is *not* available._10}
Switch​
Switch-statements compare a value against several possible values of the same type, in order. When an equal value is found, the associated block of code is executed.
The switch-statement starts with the switch
keyword, followed by the tested value,
followed by the cases inside opening and closing braces.
The test expression must be equatable.
The braces are required and not optional.
Each case is a separate branch of code execution
and starts with the case
keyword,
followed by a possible value, a colon (:
),
and the block of code that should be executed
if the case's value is equal to the tested value.
The block of code associated with a switch case does not implicitly fall through, and must contain at least one statement. Empty blocks are invalid.
An optional default case may be given by using the default
keyword.
The block of code of the default case is executed
when none of the previous case tests succeeded.
It must always appear last.
_22fun word(_ n: Int): String {_22 // Test the value of the parameter `n`_22 switch n {_22 case 1:_22 // If the value of variable `n` is equal to `1`,_22 // then return the string "one"_22 return "one"_22 case 2:_22 // If the value of variable `n` is equal to `2`,_22 // then return the string "two"_22 return "two"_22 default:_22 // If the value of variable `n` is neither equal to `1` nor to `2`,_22 // then return the string "other"_22 return "other"_22 }_22}_22_22word(1) // returns "one"_22word(2) // returns "two"_22word(3) // returns "other"_22word(4) // returns "other"
Duplicate cases​
Cases are tested in order, so if a case is duplicated, the block of code associated with the first case that succeeds is executed.
_20fun test(_ n: Int): String {_20 // Test the value of the parameter `n`_20 switch n {_20 case 1:_20 // If the value of variable `n` is equal to `1`,_20 // then return the string "one"_20 return "one"_20 case 1:_20 // If the value of variable `n` is equal to `1`,_20 // then return the string "also one"._20 // This is a duplicate case for the one above._20 return "also one"_20 default:_20 // If the value of variable `n` is neither equal to `1` nor to `2`,_20 // then return the string "other"_20 return "other"_20 }_20}_20_20word(1) // returns "one", not "also one"
break
​
The block of code associated with a switch case may contain a break
statement.
It ends the execution of the switch statement immediately
and transfers control to the code after the switch statement
No Implicit Fallthrough​
Unlike switch statements in some other languages,
switch statements in Cadence do not "fall through":
execution of the switch statement finishes as soon as the block of code
associated with the first matching case is completed.
No explicit break
statement is required.
This makes the switch statement safer and easier to use, avoiding the accidental execution of more than one switch case.
Some other languages implicitly fall through to the block of code associated with the next case, so it is common to write cases with an empty block to handle multiple values in the same way.
To prevent developers from writing switch statements that assume this behaviour, blocks must have at least one statement. Empty blocks are invalid.
_27fun words(_ n: Int): [String] {_27 // Declare a variable named `result`, an array of strings,_27 // which stores the result_27 let result: [String] = []_27_27 // Test the value of the parameter `n`_27 switch n {_27 case 1:_27 // If the value of variable `n` is equal to `1`,_27 // then append the string "one" to the result array_27 result.append("one")_27 case 2:_27 // If the value of variable `n` is equal to `2`,_27 // then append the string "two" to the result array_27 result.append("two")_27 default:_27 // If the value of variable `n` is neither equal to `1` nor to `2`,_27 // then append the string "other" to the result array_27 result.append("other")_27 }_27 return result_27}_27_27words(1) // returns `["one"]`_27words(2) // returns `["two"]`_27words(3) // returns `["other"]`_27words(4) // returns `["other"]`
Looping​
while-statement​
While-statements allow a certain piece of code to be executed repeatedly, as long as a condition remains true.
The while-statement starts with the while
keyword, followed by the condition,
and the code that should be repeatedly
executed if the condition is true inside opening and closing braces.
The condition must be boolean and the braces are required.
The while-statement will first evaluate the condition. If it is true, the piece of code is executed and the evaluation of the condition is repeated. If the condition is false, the piece of code is not executed and the execution of the whole while-statement is finished. Thus, the piece of code is executed zero or more times.
_10var a = 0_10while a < 5 {_10 a = a + 1_10}_10_10// `a` is `5`
For-in statement​
For-in statements allow a certain piece of code to be executed repeatedly for each element in an array.
The for-in statement starts with the for
keyword, followed by the name of
the element that is used in each iteration of the loop,
followed by the in
keyword, and then followed by the array
that is being iterated through in the loop.
Then, the code that should be repeatedly executed in each iteration of the loop is enclosed in curly braces.
If there are no elements in the data structure, the code in the loop will not be executed at all. Otherwise, the code will execute as many times as there are elements in the array.
_11let array = ["Hello", "World", "Foo", "Bar"]_11_11for element in array {_11 log(element)_11}_11_11// The loop would log:_11// "Hello"_11// "World"_11// "Foo"_11// "Bar"
Optionally, developers may include an additional variable preceding the element name, separated by a comma. When present, this variable contains the current index of the array being iterated through during each repeated execution (starting from 0).
_11let array = ["Hello", "World", "Foo", "Bar"]_11_11for index, element in array {_11 log(index)_11}_11_11// The loop would log:_11// 0_11// 1_11// 2_11// 3
To iterate over a dictionary's entries (keys and values), use a for-in loop over the dictionary's keys and get the value for each key:
_12let dictionary = {"one": 1, "two": 2}_12for key in dictionary.keys {_12 let value = dictionary[key]!_12 log(key)_12 log(value)_12}_12_12// The loop would log:_12// "one"_12// 1_12// "two"_12// 2
Alternatively, dictionaries carry a method forEachKey
that avoids allocating an intermediate array for keys:
_10let dictionary = {"one": 1, "two": 2, "three": 3}_10dictionary.forEachKey(fun (key: String): Bool {_10 let value = dictionary[key]_10 log(key)_10 log(value)_10_10 return key != "two" // stop iteration if this returns false_10})
Ranges in Loops​
An InclusiveRange
value can be used in a for-in statement in place of an array or dictionary. In this case,
the loop will iterate over all the values contained in the range, beginning with range.start
and ending with range.end
. E.g.
_10let range: InclusiveRange<UInt> = InclusiveRange(1, 100, step: 2)_10var elements : [UInt] = []_10for element in range {_10 elements.append(element)_10}_10// after this loop, `elements` contains all the odd integers from 1 to 99
Note that in this example, even though 100
is the end of the range
, it is not included in the loop because it cannot be reached with the given start
and step
.
The above loop is equivalent to:
_10let range: InclusiveRange<UInt> = InclusiveRange(1, 100, step: 2)_10var elements : [UInt] = []_10var index = range.start_10while index <= range.end {_10 elements.append(element)_10 index = index + range.step_10}_10// after this loop, `elements` contains all the odd integers from 1 to 99
In general, a for-in loop over an increasing range (a positive step
) is equivalent to:
_10var index = range.start_10while index <= range.end {_10 // loop body_10 index = index + range.step_10}
While a for-in loop over a decreasing range (a negative step
) is equivalent to:
_10var index = range.start_10while index >= range.end {_10 // loop body_10 index = index + range.step // `range.step` here is negative, so this decreases `index`_10}
Both can be equivalently rewritten to:
_10var index = range.start_10while range.contains(index) {_10 // loop body_10 index = index + range.step_10}
continue
and break
​
In for-loops and while-loops, the continue
statement can be used to stop
the current iteration of a loop and start the next iteration.
_22var i = 0_22var x = 0_22while i < 10 {_22 i = i + 1_22 if i < 3 {_22 continue_22 }_22 x = x + 1_22}_22// `x` is `8`_22_22_22let array = [2, 2, 3]_22var sum = 0_22for element in array {_22 if element == 2 {_22 continue_22 }_22 sum = sum + element_22}_22_22// `sum` is `3`
The break
statement can be used to stop the execution
of a for-loop or a while-loop.
_20var x = 0_20while x < 10 {_20 x = x + 1_20 if x == 5 {_20 break_20 }_20}_20// `x` is `5`_20_20_20let array = [1, 2, 3]_20var sum = 0_20for element in array {_20 if element == 2 {_20 break_20 }_20 sum = sum + element_20}_20_20// `sum` is `1`
Immediate function return: return-statement​
The return-statement causes a function to return immediately,
i.e., any code after the return-statement is not executed.
The return-statement starts with the return
keyword
and is followed by an optional expression that should be the return value of the function call.