Control flow statements employ decision-making to conditionally execute particular blocks of code and are used to break up the typical top-to-bottom flow of execution. Some examples of these kinds of statements are the well-known if-else
statements, looping statements like for
or while
, and the more versatile switch
or when
statements.
In this article, I will compare the traditional switch
statement found in the Swift programming language and the similar when
statement found in Kotlin.
Both control flow statements define a conditional expression with multiple branches, then sequentially match their arguments against all branches until some branch condition is satisfied. Finally, they execute the matched branch’s block of code and continue executing any subsequent pieces of code.
To jump ahead in this article:
switch
and when
statements in Swift and KotlinWhile Swift and Kotlin have many differences, there are some similarities that both their switch
and when
control flow statements share.
The most obvious similarity between both the switch
and when
control flow statements is the default case.
Swift’s switch
statement simply inherits the default
keyword from its C predecessors, while Kotlin instead opts to use the divergent but well-known else
keyword in order to define the default case of its modern when
statements.
Here’s an example of a switch
statement in Swift:
switch (expression) { case value1: // content case value2: // content ... default: // content of default case }
And here’s an example of a when
statement in Kotlin:
when (expression) { value1 -> //content value2 -> //content ... else -> // content of default case }
Both of these statements can be actively substituted by a series of if-else-if
statements, where the trailing else
statement serves as the default case. Nevertheless, both the switch
and when
statements achieve the same as an if-else
statement with multiple branches, but with less code and more simple syntax:
if (expression == value1) { // content } else if (expression == value2) { // content ... } else { // content of default case }
Conversely, both conditional statements can use any kind of native data type as the body or expression to use for comparison within the branches.
Some examples of the different data types they can use include Integer
, Double
, Char
, and String
types.
Here’s an example of a switch
statement comparing a Character
type in Swift:
let charToCompare: Character = "i" switch someCharacter { case "a": // content case "i": // content case "n": // content case "v": // content }
Additionally, both of these statements support the use of the Enumeration
type, also known as enum
, as the conditional expression used for comparison.
Here’s an example of a when
statement comparing an enum
type in Kotlin:
enum class Color { BLUE, PURPLE, BLACK, GOLD } when (getColor()) { Color.BLUE -> // content Color.PURPLE -> // content Color.BLACK -> // content Color.GOLD -> // content }
Notice that in the example above, all cases of the enumeration are exhausted. This allows us to omit the default case, which would have been an else
branch.
Another similarity that when
and switch
share is the ability to use numeric ranges as the values to compare against the provided expression.
Here’s an example of a switch
statement using a numeric range in Swift:
let count = 42 switch count { case 0..25: // content case 26..50: // content case 51..75: // content case 76..100: // content default: // default case content }
And here’s an example of a when
statement using a numeric range in Kotlin:
val count = 42 when (count) { in 0..25 -> // content in 26..50 -> // content in 51..75 -> // content in 76..100 -> // content else -> // default case content }
switch
and when
statementsWith both the switch
and when
statements, it is also possible to group more than one case in the same conditional branch by simply separating all additional conditions with a comma.
Here’s an example of a when
statement capturing multiple cases in one branch in Kotlin:
val x = 6 when (x) { in 1, 2 -> // content in 3, 4 -> // content in 5, 6 -> // content else -> // default case content }
Another powerful similarity that both when
and switch
share is the ability to check for inheritance. We can do this by checking what kind of object we’re dealing with, as long as the expression to compare is an instance of a superclass.
Here’s an example of a switch
statement checking for object type in Swift:
let vehicle: Vehicle = Car() switch vehicle { case is Car: // content case is Motorcycle: // content case is Tricycle: //content } // where Car, Motorcycle & Tricycle all extend the Vehicle class
switch
and when
statementsThe last similarity that we’ll go over is something that both expressions can do because of the functional programming patterns that both Swift and Kotlin have integrated into their language libraries.
We can use either switch
or when
statements as the assignment of a variable, where both will take the result they’re arriving at and use it as the value for any kind of variable.
Here’s an example of a when
statement being assigned to a variable in Kotlin:
val seasonOfTheYear: String = when (getMonthByNumber()) { 3, 4, 5 -> "Spring" 6, 7, 8 -> "Summer" 9, 10, 11 -> "Autumn" 12, 1, 2 -> "Winter" }
switch
and when
statementsWhile there are a lot of similarities between Swift’s switch
and Kotlin’s when
statements, they also have some fundamental differences, thanks to the unique features of their respective programming languages.
switch
statementThe first difference worth noting between switch
and when
is that while Swift’s switch
statement has to be exhaustive at all times, and while adding a default branch may be enough to make it exhaustive at the compiler level, this is not the case for Kotlin’s when
statement.
The Kotlin when
statement is only required to be exhaustive when it is used as an expression — for example, whenever it gets assigned to a variable, or where an else
branch may be used to capture a default behavior. On the other hand, whenever the when
pattern is used as a statement, it behaves as a regular if-else-if
statement, where all branches of the conditional block will be assessed, but no branch will execute unless there’s a match.
Fallthrough
cases in Swift and KotlinGetting back into code, a big distinction between the switch
and when
expressions is the use of the fallthrough
keyword.
The fallthrough
behavior in Swift works a lot like it does in a C-based language. For example, in the Java code block below, omitting the break
keyword triggers the fallthrough
behavior by executing the code that is contained by the next conditional branch of the switch
statement.
final int x = 6; switch { case 1, 2: // not executed break; case 3, 4: // not executed break; case 5, 6: // executed case 7, 8, 9: // also executed because it will fall through break; }
In contract, Swift switch
statement requires a special keyword, namely fallthrough
, to indicate that we want any given conditional branch of a switch
statement to fall through onto the next one and execute the code that is in there as well.
Here’s an example of a switch
statement with fallthrough
behavior in Swift:
let x = 6 switch x { case 1, 2: // not executed case 3, 4: // not executed case 5, 6: // executed fallthrough case 7, 8, 9: // also executed because it will fall through }
when
advantage: Conditional statement with an empty expressionMoving over into the Kotlin scene, the when
statement has an advantage: it can be used with an explicit body or expression, allowing it to enter a typical if-else-if
pattern, but with a much cleaner syntax.
Whenever taking this approach, the else
branch is also available as a default case, but it’s not required in all cases.
Here’s an example of a when
statement with an empty expression in Kotlin:
when { x.isOdd() -> // content x.isEven -> // content else -> // default case content }
Bonus: There is a hacky way of achieving this in a
switch
statement where you simply passtrue
as your expression and go over each branch one by one, but this case shouldn’t be chosen over a regularif-else-if
tree of expressions.
switch
statement’s expressionThe last difference between when
and switch
we’ll cover comes from a pattern deeply engrained into Swift that comprises passing a tuple as the switch
statement’s expression.
Although this data structure type is similar to a regular Java or Kotlin Pair
, it does not directly support when
statements receiving this as their expression, and it is not used in the same way that Swift uses it by comparing two values at once.
Here’s an example of a switch
statement using a tuple in Swift:
let coordinates = (0, 1) switch coordinates { case (0, 0): // point is at the center case (_, 0): // point is on the x-axis case (0, _): // point is on the y-axis }
It’s no secret that while Swift built upon the traditional usage of switch
statements from C-based languages, Kotlin went a bit astray by transforming its when
statement with conditional branching.
However, these statements share many similarities while also sporting differences based on the patterns and paradigms supported by each of their programming languages.
At the end of the day, both switch
and when
statements should be used with the same goal in mind: to break out of the usual top-to-bottom sequence of execution and to add decision-making, flexibility, and versatility to our classes.
LogRocket is an Android monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your Android apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your Android apps — try LogRocket for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.