Skip to content

Commit 93f70ee

Browse files
committed
update: update when section
1 parent 304902d commit 93f70ee

File tree

10 files changed

+155
-67
lines changed

10 files changed

+155
-67
lines changed

docs/topics/advent-of-code.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ or watch the video:
230230

231231
### Day 4: Passport processing
232232

233-
Apply the [`when`](control-flow.md#when-expression) expression and explore different ways of how to validate the input:
233+
Apply the [`when`](control-flow.md#when-expressions-and-statements) expression and explore different ways of how to validate the input:
234234
utility functions, working with ranges, checking set membership, and matching a particular regular expression.
235235

236236
* Read the puzzle description on [Advent of Code](https://adventofcode.com/2020/day/4)

docs/topics/basic-syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ fun main() {
437437
```
438438
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-basic-syntax-when-expression"}
439439

440-
See [when expression](control-flow.md#when-expression).
440+
See [when expressions and statements](control-flow.md#when-expressions-and-statements).
441441

442442
## Ranges
443443

docs/topics/control-flow.md

Lines changed: 141 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ fun main() {
2727
// You can also use `else if` in expressions:
2828
val maxLimit = 1
2929
val maxOrLimit = if (maxLimit > a) maxLimit else if (a > b) a else b
30-
31-
//sampleEnd
30+
3231
println("max is $max")
32+
// max is 3
3333
println("maxOrLimit is $maxOrLimit")
34+
// maxOrLimit is 3
35+
//sampleEnd
3436
}
3537
```
3638
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="if-else-if-kotlin"}
@@ -50,71 +52,152 @@ val max = if (a > b) {
5052
If you're using `if` as an expression, for example, for returning its value or
5153
assigning it to a variable, the `else` branch is mandatory.
5254

53-
## When expression
55+
## When expressions and statements
56+
57+
`when` is a conditional expression that runs code based on multiple possible values or conditions. It is
58+
similar to the `switch` statement in Java, C, and similar languages. For example:
59+
60+
```kotlin
61+
fun main() {
62+
//sampleStart
63+
val x = 2
64+
when (x) {
65+
1 -> print("x == 1")
66+
2 -> print("x == 2")
67+
else -> print("x is neither 1 nor 2")
68+
}
69+
// x == 2
70+
//sampleEnd
71+
}
72+
```
73+
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-conditions-when-statement"}
74+
75+
`when` matches its argument against all branches sequentially until some branch condition is satisfied.
76+
77+
You can use `when` in a few different ways. Firstly, you can use `when` either as an **expression** or as a **statement**.
78+
As an expression, `when` returns a value for later use in your code. As a statement, `when` completes an action
79+
without returning anything of further use:
80+
81+
<table>
82+
<tr>
83+
<td>Expression</td>
84+
<td>Statement</td>
85+
</tr>
86+
<tr>
87+
<td>
88+
89+
```kotlin
90+
// Returns a string assigned to the
91+
// text variable
92+
val text = when (x) {
93+
1 -> "x == 1"
94+
2 -> "x == 2"
95+
else -> "x is neither 1 nor 2"
96+
}
97+
```
5498

55-
`when` defines a conditional expression with multiple branches. It is similar to the `switch` statement in C-like languages.
56-
Its simple form looks like this.
99+
</td>
100+
<td>
57101

58102
```kotlin
103+
// Returns nothing but triggers a
104+
// print statement
59105
when (x) {
60106
1 -> print("x == 1")
61107
2 -> print("x == 2")
62-
else -> {
63-
print("x is neither 1 nor 2")
64-
}
108+
else -> print("x is neither 1 nor 2")
65109
}
66110
```
67111

68-
`when` matches its argument against all branches sequentially until some branch condition is satisfied.
112+
</td>
113+
</tr>
114+
</table>
69115

70-
`when` can be used either as an expression or as a statement. If it is used as an expression, the value
71-
of the first matching branch becomes the value of the overall expression. If it is used as a statement, the values of
72-
individual branches are ignored. Just like with `if`, each branch can be a block, and its value
73-
is the value of the last expression in the block.
116+
Secondly, you can use `when` with or without a subject. Whether you use a subject with `when` or not, your expression or
117+
statement behaves the same. We recommend using `when` with a subject when possible, as it makes your code easier to read
118+
and maintain by clearly showing what you're checking.
74119

75-
The `else` branch is evaluated if none of the other branch conditions are satisfied.
120+
<table>
121+
<tr>
122+
<td>With subject <code>x</code></td>
123+
<td>Without subject</td>
124+
</tr>
125+
<tr>
126+
<td>
76127

77-
If `when` is used as an _expression_, the `else` branch is mandatory,
78-
unless the compiler can prove that all possible cases are covered with branch conditions,
79-
for example, with [`enum` class](enum-classes.md) entries and [`sealed` class](sealed-classes.md) subtypes).
128+
```kotlin
129+
when(x) { ... }
130+
```
131+
132+
</td>
133+
<td>
134+
135+
```kotlin
136+
when { ... }
137+
```
138+
139+
</td>
140+
</tr>
141+
</table>
142+
143+
Depending on how you use `when`, there are different requirements for whether you need to cover all possible cases in your
144+
branches.
145+
146+
If you use `when` as a statement, you don't have to cover all possible cases. In this example, some cases aren't covered,
147+
so nothing happens. However, no error occurs:
148+
149+
```kotlin
150+
fun main() {
151+
//sampleStart
152+
val x = 3
153+
when (x) {
154+
// Not all cases are covered
155+
1 -> print("x == 1")
156+
2 -> print("x == 2")
157+
}
158+
//sampleEnd
159+
}
160+
```
161+
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-statement"}
162+
163+
In a `when` statement, the values of individual branches are ignored. Just like with `if`, each branch can be a block,
164+
and its value is the value of the last expression in the block.
165+
166+
If you use `when` as an expression, you have to cover all possible cases. In other words, it must be _exhaustive_.
167+
The value of the first matching branch becomes the value of the overall expression. If you don't cover all cases,
168+
the compiler throws an error.
169+
170+
If your `when` expression has a subject, you can use an `else` branch to make sure that all possible cases are covered, but
171+
it isn't mandatory. For example, if your subject is a `Boolean`, [`enum` class](enum-classes.md), [`sealed` class](sealed-classes.md),
172+
or one of their nullable counterparts, you can cover all cases without an `else` branch:
80173

81174
```kotlin
82175
enum class Bit {
83176
ZERO, ONE
84177
}
85178

86179
val numericValue = when (getRandomBit()) {
180+
// No else branch is needed because all cases are covered
87181
Bit.ZERO -> 0
88182
Bit.ONE -> 1
89-
// 'else' is not required because all cases are covered
90183
}
91184
```
92185

93-
In `when` _statements_, the `else` branch is mandatory in the following conditions:
94-
* `when` has a subject of a `Boolean`, [`enum`](enum-classes.md),
95-
or [`sealed`](sealed-classes.md) type, or their nullable counterparts.
96-
* branches of `when` don't cover all possible cases for this subject.
186+
If your `when` expression **doesn't** have a subject, you **must** have an `else` branch or the compiler throws an error.
187+
The `else` branch is evaluated when none of the other branch conditions are satisfied:
97188

98189
```kotlin
99-
enum class Color {
100-
RED, GREEN, BLUE
101-
}
102-
103-
when (getColor()) {
104-
Color.RED -> println("red")
105-
Color.GREEN -> println("green")
106-
Color.BLUE -> println("blue")
107-
// 'else' is not required because all cases are covered
108-
}
109-
110-
when (getColor()) {
111-
Color.RED -> println("red") // no branches for GREEN and BLUE
112-
else -> println("not red") // 'else' is required
190+
when {
191+
a > b -> "a is greater than b"
192+
a < b -> "a is less than b"
193+
else -> "a is equal to b"
113194
}
114195
```
115196

197+
`when` expressions and statements offer different ways to simplify your code, handle multiple conditions, and perform
198+
type checks.
116199

117-
To define a common behavior for multiple cases, combine their conditions in a single line with a comma:
200+
You can define a common behavior for multiple cases by combining their conditions in a single line with a comma:
118201

119202
```kotlin
120203
when (x) {
@@ -123,7 +206,7 @@ when (x) {
123206
}
124207
```
125208

126-
You can use arbitrary expressions (not only constants) as branch conditions
209+
You can use arbitrary expressions (not only constants) as branch conditions:
127210

128211
```kotlin
129212
when (x) {
@@ -132,7 +215,7 @@ when (x) {
132215
}
133216
```
134217

135-
You can also check a value for being `in` or `!in` a [range](ranges.md) or a collection:
218+
You can also check whether a value is or isn't contained in a [range](ranges.md) or collection via the `in` or `!in` keywords:
136219

137220
```kotlin
138221
when (x) {
@@ -143,9 +226,9 @@ when (x) {
143226
}
144227
```
145228

146-
Another option is checking that a value `is` or `!is` of a particular type. Note that,
147-
due to [smart casts](typecasts.md#smart-casts), you can access the methods and properties of the type without
148-
any extra checks.
229+
Additionally, you can check that a value is or isn't a particular type via the `is` or `!is` keywords. Note that,
230+
due to [smart casts](typecasts.md#smart-casts), you can access the member functions and properties of the type without
231+
any additional checks.
149232

150233
```kotlin
151234
fun hasPrefix(x: Any) = when(x) {
@@ -154,8 +237,8 @@ fun hasPrefix(x: Any) = when(x) {
154237
}
155238
```
156239

157-
`when` can also be used as a replacement for an `if`-`else` `if` chain.
158-
If no argument is supplied, the branch conditions are simply boolean expressions, and a branch is executed when its condition is true:
240+
You can use `when` as a replacement for an `if`-`else` `if` chain.
241+
If there's no subject, the branch conditions are simply boolean expressions, and a branch is run when its condition is true:
159242

160243
```kotlin
161244
when {
@@ -165,7 +248,7 @@ when {
165248
}
166249
```
167250

168-
You can capture *when* subject in a variable using following syntax:
251+
You can capture the subject in a variable by using the following syntax:
169252

170253
```kotlin
171254
fun Request.getBody() =
@@ -175,7 +258,7 @@ fun Request.getBody() =
175258
}
176259
```
177260

178-
The scope of variable introduced in *when* subject is restricted to the body of this *when*.
261+
The scope of a variable introduced as the subject is restricted to the body of the `when` expression or statement.
179262

180263
## For loops
181264

@@ -208,11 +291,12 @@ To iterate over a range of numbers, use a [range expression](ranges.md):
208291
fun main() {
209292
//sampleStart
210293
for (i in 1..3) {
211-
println(i)
294+
print(i)
212295
}
213296
for (i in 6 downTo 0 step 2) {
214-
println(i)
297+
print(i)
215298
}
299+
// 1236420
216300
//sampleEnd
217301
}
218302
```
@@ -227,8 +311,9 @@ fun main() {
227311
val array = arrayOf("a", "b", "c")
228312
//sampleStart
229313
for (i in array.indices) {
230-
println(array[i])
314+
print(array[i])
231315
}
316+
// abc
232317
//sampleEnd
233318
}
234319
```
@@ -243,18 +328,21 @@ fun main() {
243328
for ((index, value) in array.withIndex()) {
244329
println("the element at $index is $value")
245330
}
331+
// the element at 0 is a
332+
// the element at 1 is b
333+
// the element at 2 is c
246334
//sampleEnd
247335
}
248336
```
249337
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
250338

251339
## While loops
252340

253-
`while` and `do-while` loops execute their body continuously while their condition is satisfied.
341+
`while` and `do-while` loops process their body continuously while their condition is satisfied.
254342
The difference between them is the condition checking time:
255-
* `while` checks the condition and, if it's satisfied, executes the body and then returns to the condition check.
256-
* `do-while` executes the body and then checks the condition. If it's satisfied, the loop repeats. So, the body of `do-while`
257-
executes at least once regardless of the condition.
343+
* `while` checks the condition and, if it's satisfied, processes the body and then returns to the condition check.
344+
* `do-while` processes the body and then checks the condition. If it's satisfied, the loop repeats. So, the body of `do-while`
345+
runs at least once regardless of the condition.
258346

259347
```kotlin
260348
while (x > 0) {

docs/topics/keyword-reference.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@ The following tokens are always interpreted as keywords and cannot be used as id
2121
- specifies the object being iterated in a [for loop](control-flow.md#for-loops).
2222
- is used as an infix operator to check that a value belongs to [a range](ranges.md),
2323
a collection, or another entity that [defines a 'contains' method](operator-overloading.md#in-operator).
24-
- is used in [when expressions](control-flow.md#when-expression) for the same purpose.
24+
- is used in [when expressions](control-flow.md#when-expressions-and-statements) for the same purpose.
2525
- marks a type parameter as [contravariant](generics.md#declaration-site-variance).
2626
* `!in`
2727
- is used as an operator to check that a value does NOT belong to [a range](ranges.md),
2828
a collection, or another entity that [defines a 'contains' method](operator-overloading.md#in-operator).
29-
- is used in [when expressions](control-flow.md#when-expression) for the same purpose.
29+
- is used in [when expressions](control-flow.md#when-expressions-and-statements) for the same purpose.
3030
* `interface` declares an [interface](interfaces.md).
3131
* `is`
3232
- checks that [a value has a certain type](typecasts.md#is-and-is-operators).
33-
- is used in [when expressions](control-flow.md#when-expression) for the same purpose.
33+
- is used in [when expressions](control-flow.md#when-expressions-and-statements) for the same purpose.
3434
* `!is`
3535
- checks that [a value does NOT have a certain type](typecasts.md#is-and-is-operators).
36-
- is used in [when expressions](control-flow.md#when-expression) for the same purpose.
36+
- is used in [when expressions](control-flow.md#when-expressions-and-statements) for the same purpose.
3737
* `null` is a constant representing an object reference that doesn't point to any object.
3838
* `object` declares [a class and its instance at the same time](object-declarations.md).
3939
* `package` specifies the [package for the current file](packages.md).
@@ -51,7 +51,7 @@ The following tokens are always interpreted as keywords and cannot be used as id
5151
* `typeof` is reserved for future use.
5252
* `val` declares a read-only [property](properties.md) or [local variable](basic-syntax.md#variables).
5353
* `var` declares a mutable [property](properties.md) or [local variable](basic-syntax.md#variables).
54-
* `when` begins a [when expression](control-flow.md#when-expression) (executes one of the given branches).
54+
* `when` begins a [when expression](control-flow.md#when-expressions-and-statements) (executes one of the given branches).
5555
* `while` begins a [while loop](control-flow.md#while-loops) (a loop with a precondition).
5656

5757
## Soft keywords
@@ -153,7 +153,7 @@ Kotlin supports the following operators and special symbols:
153153
* `->`
154154
- separates the parameters and body of a [lambda expression](lambdas.md#lambda-expression-syntax).
155155
- separates the parameters and return type declaration in a [function type](lambdas.md#function-types).
156-
- separates the condition and body of a [when expression](control-flow.md#when-expression) branch.
156+
- separates the condition and body of a [when expression](control-flow.md#when-expressions-and-statements) branch.
157157
* `@`
158158
- introduces an [annotation](annotations.md#usage).
159159
- introduces or references a [loop label](returns.md#break-and-continue-labels).

docs/topics/sealed-classes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ you can create subclasses in any source set between the `expect` and `actual` de
164164

165165
## Use sealed classes with when expression
166166

167-
The key benefit of using sealed classes comes into play when you use them in a [`when`](control-flow.md#when-expression)
167+
The key benefit of using sealed classes comes into play when you use them in a [`when`](control-flow.md#when-expressions-and-statements)
168168
expression.
169169
The `when` expression, used with a sealed class, allows the Kotlin compiler to check exhaustively that all possible cases are covered.
170170
In such cases, you don't need to add an `else` clause:

docs/topics/typecasts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ print(x.length) // x is automatically cast to String
4747

4848
### Control flow
4949

50-
Smart casts work not only for `if` conditional expressions but also for [`when` expressions](control-flow.md#when-expression)
50+
Smart casts work not only for `if` conditional expressions but also for [`when` expressions](control-flow.md#when-expressions-and-statements)
5151
and [`while` loops](control-flow.md#while-loops):
5252

5353
```kotlin

0 commit comments

Comments
 (0)