Guard Conditions in when Statements in Kotlin 2.1.0

Kotlin 2.1 introduces guard conditions in when statements, a feature that allows combining condition matching and boolean checks in a concise and readable way.

Before Kotlin 2.1 introduced guard conditions in when statements, developers had to rely on nested if statements or multiple branches to achieve the same functionality.

For Android developers, this feature simplifies handling complex scenarios like API responses, user inputs, and dynamic UI behavior.

In this blog, we’ll explore:

  1. How to enable this feature.

  2. Using guard conditions with when.

  3. Practical examples, including else if branches.

  4. Tips for clean, maintainable code.

What Are Guard Conditions in when Statements?

A guard condition is an additional if clause in a when branch that allows you to add boolean checks for a matched condition. This reduces nested if statements and makes your code more expressive.

Syntax

when (val subject = expression) {
    condition if guardExpression -> { /* action */ }
    else if anotherCondition -> { /* alternate action */ }
    else -> { /* fallback action */ }
}

Let’s compare how code looks in older Kotlin versions versus the new Kotlin 2.1 feature, and why this enhancement is so useful.

How when Worked in Older Kotlin Versions

In previous versions of Kotlin (before 2.1), handling additional boolean checks with when required writing nested if statements or duplicating logic for different cases. Here’s an example:

Old Kotlin Implementation

fun validateCredentialsOld(username: String, password: String): String {
    return when (username) {
        "admin" -> {
            if (password.isEmpty()) {
                "Password cannot be empty for admin."
            } else if (password == "admin123") {
                "Welcome, Admin!"
            } else {
                "Invalid admin password."
            }
        }
        else -> {
            if (username.isEmpty()) {
                "Username cannot be empty."
            } else if (password.isEmpty()) {
                "Password cannot be empty."
            } else {
                "Invalid credentials. Please try again."
            }
        }
    }
}

In the old approach:

  1. We needed nested if statements inside when branches to handle additional conditions.

  2. Logic became harder to follow and less readable, especially as complexity increased.

  3. Repeated checks (e.g., password.isEmpty()) led to code duplication.

How the New Feature Simplifies This

With Kotlin 2.1’s guard conditions, additional checks can now be written inline within when branches using the if keyword. This avoids nesting, reduces duplication, and improves readability.

New Kotlin Implementation (with Guard Conditions)

fun validateCredentials(username: String, password: String): String {
    return when (username) {
        "admin" if password.isEmpty() -> "Password cannot be empty for admin."
        "admin" if password == "admin123" -> "Welcome, Admin!"
        else if username.isEmpty() -> "Username cannot be empty."
        else if password.isEmpty() -> "Password cannot be empty."
        else -> "Invalid credentials. Please try again."
    }
}

Advantages of the New Feature:

  1. No nesting: Guard conditions make additional checks concise and inline.

  2. Improved readability: Each branch is self-contained, making the logic easier to understand.

  3. Reduced duplication: Avoid repeating logic in multiple branches.

How to Implement Guard Conditions in Old Kotlin Versions

If you're working in a version of Kotlin that doesn’t support guard conditions, you can replicate similar behavior by:

  1. Using if blocks inside when branches.

  2. Refactoring into helper functions to reduce nested logic.

Example: Replicating Guard Conditions in Older Versions

Here’s how you can simulate guard conditions in Kotlin versions before 2.1:

fun validateCredentialsOld(username: String, password: String): String {
    return when {
        username == "admin" && password.isEmpty() -> "Password cannot be empty for admin."
        username == "admin" && password == "admin123" -> "Welcome, Admin!"
        username.isEmpty() -> "Username cannot be empty."
        password.isEmpty() -> "Password cannot be empty."
        else -> "Invalid credentials. Please try again."
    }
}

In this example:

  • when uses compound conditions (&&) to handle cases.

  • The nested if statements are removed by moving the logic directly into the condition checks.

Use Cases in Android Development

1. Validating User Input with else if

Consider a login form where you validate the username and password with nuanced error handling:

fun validateCredentials(username: String, password: String): String {
    return when (username) {
        "admin" if password.isEmpty() -> "Password cannot be empty for admin."
        "admin" if password == "admin123" -> "Welcome, Admin!"
        else if username.isEmpty() -> "Username cannot be empty."
        else if password.isEmpty() -> "Password cannot be empty."
        else -> "Invalid credentials. Please try again."
    }
}

Key Points:

  • The else if branches allow catching additional cases like empty usernames or passwords.

  • The else branch acts as a fallback for unmatched cases.

2. Processing API Responses with else if

When handling API responses, you often need to process both success and error cases. Guard conditions with else if simplify this.

fun handleApiResponse(statusCode: Int, errorMessage: String?): String {
    return when (statusCode) {
        200 if errorMessage == null -> "Success! Data loaded."
        400 if errorMessage != null -> "Client Error: $errorMessage"
        500 -> "Server Error: Try again later."
        else if statusCode in 401..499 -> "Authentication Error: Code $statusCode"
        else -> "Unknown Response."
    }
}

Key Points:

  • The else if handles a range of status codes (401–499) as authentication errors.

  • Additional error handling logic stays clean and focused.

3. Customizing Themes Based on User Preferences

Dynamic themes are common in Android apps. Use guard conditions to handle multiple parameters like orientation and user preferences.

fun getThemeColor(orientation: Int, isDarkMode: Boolean, isHighContrast: Boolean): Int {
    return when (orientation) {
        Configuration.ORIENTATION_PORTRAIT if isDarkMode -> Color.BLACK
        Configuration.ORIENTATION_PORTRAIT if isHighContrast -> Color.YELLOW
        Configuration.ORIENTATION_LANDSCAPE if isDarkMode -> Color.DARK_GRAY
        else if isHighContrast -> Color.ORANGE
        else -> Color.WHITE
    }
}

Key Points:

  • Guard conditions (if isDarkMode, if isHighContrast) make conditions specific and easier to read.

  • The else if branch ensures fallback customization for high contrast mode.

Using Guard Conditions in Jetpack Compose

Jetpack Compose simplifies UI updates, and guard conditions make declarative logic easier. Here’s an example with else if for dynamic styling:

@Composable
fun UserRoleDisplay(role: String, isVerified: Boolean, isPremium: Boolean) {
    val textStyle = when (role) {
        "Admin" if isVerified -> TextStyle(color = Color.Red, fontWeight = FontWeight.Bold)
        "User" if isVerified -> TextStyle(color = Color.Green, fontWeight = FontWeight.Normal)
        "Guest" -> TextStyle(color = Color.Gray, fontStyle = FontStyle.Italic)
        else if isPremium -> TextStyle(color = Color.Gold, fontWeight = FontWeight.Medium)
        else -> TextStyle(color = Color.Black)
    }

    Text(
        text = "Role: $role",
        style = textStyle
    )
}

Key Points:

  • Guard conditions (if isVerified, if isPremium) determine the user’s style dynamically.

  • The else if branch ensures premium users have a unique style even if they’re not explicitly matched by the when conditions.

Best Practices for Guard Conditions

  1. Enable Fallbacks: Always include an else branch to handle unexpected cases.

  2. Use else if Wisely: Avoid chaining too many else if branches, as it may reduce readability. Use helper functions for complex conditions.

  3. Keep It Readable: Use guard conditions only when they improve clarity. Overcomplicating a single branch can lead to hard-to-read code.

Enabling Guard Conditions in Kotlin

The guard conditions feature is currently experimental in Kotlin 2.1. To use it, you need to enable it in your project.

1. Using the Command Line

If you're running Kotlin files from the command line, use the following command:

kotlinc -Xwhen-guards main.kt

2. Configuring in Gradle

For Gradle-based projects (typical in Android development), enable it in your build.gradle.kts:

kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xwhen-guards")
    }
}

Conclusion

Guard conditions in when statements are a fantastic addition in Kotlin 2.1, enabling more expressive and readable code. For Android developers, this feature is particularly valuable in scenarios like:

  • Validating user input.

  • Handling API responses.

  • Customizing UI themes and styles.

By enabling this feature and using it wisely, you can streamline logic handling in your Kotlin projects. Experiment with when guards and elevate your Android development experience!

Akshay Nandwana
Founder AndroidEngineers

You can connect with me on:


Book 1:1 Session here
Click Here

Join our upcoming classes
https://www.androidengineers.in/courses

Love from our past students

Excellent list of questions really helped me to coverup all the topics before interview.

Saiteja Janjirala

10th Oct, 2024

I had an exceptional experience with the 1:1 mentorship session. Akshay was incredibly friendly and provided invaluable guidance on focusing on long-term goals. They also gave great interview tips, including a thorough resume review. Additionally, the discussion on Data Structures and Algorithms (DSA) was insightful and practical. Highly recommended for anyone looking to advance their career!

Nayab khan

11th Sep, 2024

Cleared my major points for what I am missing in the resume and also suggested what I can work on for further growth in the career.

Ketan Chaurasiya

7th Aug, 2024

What impressed me most was his personalized approach and practical tips that I could immediately apply. Akshay’s guidance not only improved my technical skills but also boosted my confidence in navigating my career path. His insights and encouragement have been a game-changer for me. I highly recommend Akshay’s mentorship to anyone looking to advance their Android development career.

Hardik Kubavat

5th Aug, 2024

2025© Made with   by Android Engineers.