With the release of Kotlin 2.1.0, developers now have access to a long-awaited improvement for the when statement: guard conditions. This addition enhances the readability and flexibility of your code by allowing you to specify additional conditions (guards) when evaluating cases in a when statement.

Let’s dive into what this new feature is, why it’s important, and how to enable and use it in your projects.

A guard standing at a gate, ensuring only those who meet the conditions are allowed through.

What Are Guard Conditions?

Guard conditions add an extra layer of logic to when statements by allowing you to perform additional checks beyond the standard type or value evaluations. Previously, you might have been forced to use an additional when statement or if expression. Now, you can define complex conditions directly within a single case.

Example: With and Without Guard Conditions

To illustrate the benefit of guard conditions, consider this scenario where you’re working with a sealed class HttpResult

sealed interface HttpResult {
    data class Success(val response: String) : HttpResult
    data class Failed(val statusCode: Int) : HttpResult
}

With Guard Conditions

when (response) {
    is HttpResult.Success -> println("Success")
    is HttpResult.Failed if response.statusCode == 503 -> println("Maintenance")
    is HttpResult.Failed -> println("Failed with code ${response.statusCode}")
}

Here, the logic for handling HttpResult.Failed with a specific status code (503) is seamlessly integrated into the when statement, keeping the code concise and readable.

Without Guard Conditions

Before guard conditions, you would need to write the logic like this:

when (response) {
    is HttpResult.Success -> println("Success")
    is HttpResult.Failed -> {
        if (response.statusCode == 503) {
            println("Maintenance")
        } else {
            println("Failed with code ${response.statusCode}")
        }
    }
}

This approach requires nesting an if statement inside the when block, making the code less concise and harder to read.

Important: when Must Still Be Exhaustive

Although guard conditions offer extra flexibility, an important property of when statements remains: exhaustive. The compiler will still require you to cover all possible cases in a when statement, especially when working with a sealed class.

For example, the following code will result in a compilation error because not all cases of HttpResult are handled:

when (response) {
    is HttpResult.Success -> println("Success")
    is HttpResult.Failed if response.statusCode == 503 -> println("Maintenance")
}

To fix this, you must add a case for all other instances of HttpResult.Failed, ensuring the when statement is exhaustive by adding is is HttpResult.Failed ->

How to Enable It?

This feature is In preview, and opt-in is required and must be explicitly enabled in your project. Follow these steps:

1. Enable the K2 Compiler in IntelliJ IDEA/Android Studio

To use guard conditions, you need to activate the K2 compiler in IntelliJ IDEA or Android Studio:

  • Go to Settings | Languages & Frameworks | Kotlin.
  • Check Enable K2 mode, enable or disable this option requires a restart of the IDE.

The K2 compiler is required to support new Kotlin features, including guard conditions.

2. Add Compiler Option in build.gradle.kts

Next, add the following configuration to your build.gradle.kts to enable guard conditions in the Kotlin compiler:

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

Where Can This Be Used?

Guard conditions are particularly useful in scenarios where:

  • You deal with complex when statements and specific checks.
  • You use sealed classes or enums to elegantly handle polymorphism.
  • You want to keep your logic clean and concise when evaluating various combinations of values and states.

Conclusion

The introduction of guard conditions in Kotlin 2.1.0 is a small but powerful improvement that simplifies writing clear and maintainable code. However, keep in mind that when statements must still be exhaustive. This ensures your logic remains robust, even with the added flexibility.

Make sure to enable the new feature with the configuration above and experience how your when statements can become cleaner and more expressive!