Kotlin
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Null Safety
-
Section 4: Object-Oriented Kotlin
-
Section 5: Functional Kotlin
-
Section 6: Coroutines
-
Section 7: Collections Deep Dive
-
Section 8: Type System Deep Dive
-
Section 9: Interop and Tooling
-
Section 10: Kotlin DSLs and Patterns
-
Section 11: Testing and Quality
-
Section 12: Server-Side Kotlin
-
Section 13: Practical Projects
-
Section 14: Interview Practice
-
Section 15: More Practice Exercises
-
Section 16: More Standard Library
-
Section 17: Multiplatform Kotlin
-
Section 18: kotlin.collections In Depth
-
Section 19: kotlin.text In Depth
-
Section 20: kotlin.ranges and kotlin.sequences
-
Section 21: kotlin.io and File Handling
-
Section 22: kotlinx.coroutines Deep Dive
-
Section 23: kotlin.reflect
-
Section 24: Android Development with Kotlin Overview
-
Section 25: Kotlin Multiplatform Deep Dive
-
Section 26: Kotlin for Backend Deep Dive
-
Section 27: Kotlin Design Patterns
-
Section 28: Advanced Language Features
-
Section 29: More Practice Exercises
-
Section 30: More Interview Practice
-
Section 31: Kotlin Type System Deep Dive
-
Section 32: Kotlin Null Safety Advanced
-
Section 33: Kotlin Testing Deep Dive
-
Section 34: Kotlin Build Tooling Deep Dive
-
Section 35: Kotlin Serialization
-
Section 36: Kotlin Performance Considerations
-
Section 37: Kotlin Native Overview
-
Section 38: Kotlin for Data and Scripting
-
Section 39: More Coroutines Practice
-
Section 40: More Android-Adjacent Patterns
-
Section 41: More Practical Projects
-
Section 42: More Design and Architecture Practice
-
Section 43: Kotlin Language Evolution
-
Section 44: More Interview and Review
-
Section 45: Kotlin Delegation Patterns Deep Dive
-
Section 46: Kotlin Annotations Deep Dive
-
Section 47: Kotlin for Gradle Plugin Development
-
Section 48: Kotlin Concurrency Beyond Coroutines
-
Section 49: Kotlin Compiler Internals
-
Section 50: Real-World Kotlin Case Studies
-
Section 51: Final Practice Projects
-
Section 52: Kotlin for Server-Side Reactive Programming
-
Section 53: More Practice and Drills
-
Section 54: Kotlin Security Practices
47: Contracts for Smart Compiler Analysis
I've seen this exact scenario play out in countless pull requests. You're trying to keep your code DRY by moving a null check or a validation check into a helper function, but the Kotlin compiler suddenly starts fighting you. You know the value isn't null, but the compiler refuses to believe you.
The Smart Cast that Refuses to Cast
Take a look at this snippet. I'm trying to build a simple validator for a user profile. I want to make sure the username isn't null or empty before I process it.
fun isUsernameValid(name: String?): Boolean {
return !name.isNullOrBlank()
}
fun processProfile(username: String?) {
if (isUsernameValid(username)) {
// ERROR: Smart cast to 'String' is impossible, because 'username' is a mutable property
// (or in this case, the compiler just doesn't know what happened inside the function)
println("Processing user: ${username.length}")
}
}
If you try to compile this, you'll get a type mismatch error on username.length. Even though isUsernameValid returns true only if the string is not null, the compiler isn't "smart" enough to look inside that function and carry that knowledge back to the processProfile scope. To the compiler, isUsernameValid is just a black box that returns a boolean; it has no idea that the boolean is logically tied to the nullability of the input.
Teaching the Compiler with Contracts
This is where kotlin.contracts comes in. Contracts allow you to explicitly tell the compiler: "Hey, if this function returns true, you can safely assume this variable is not null." It's basically a way of documenting the behavior of your function in a way that the compiler can actually use for static analysis.
Here is how we fix the validation logic. We need to import kotlin.contracts.contract and kotlin.contracts.returns.
import kotlin.contracts.*
fun isUsernameValid(name: String?): Boolean {
contract {
returns(true) implies (name != null)
}
return !name.isNullOrBlank()
}
fun processProfile(username: String?) {
if (isUsernameValid(username)) {
// Now this works! The compiler knows username is String, not String?
println("Processing user: ${username.length}")
}
}
By adding that contract block, we've bridged the gap. The line returns(true) implies (name != null) tells the compiler that a true result is a guarantee of non-nullability. Now, the smart cast triggers perfectly inside the if block.
When to Actually Use This
I'll be honest: you won't use contracts in every single function. Most of the time, Kotlin's standard library handles this for you (which is why ?.let {} or if (x != null) just work). However, you should reach for contracts when:
- You are building a library or a shared utility module where other developers will rely on your validation helpers.
- You have complex validation logic that would be messy to repeat inside every
ifstatement. - You want to avoid the "double-bang" operator (
!!) without wrapping every single call in aletblock.
Just a heads-up: contracts are currently an experimental feature (though very stable in practice). You might see a compiler warning asking you to opt-in using @OptIn(ExperimentalContractsApi::class) depending on your project configuration. Don't let that scare you; it's the standard way to handle these specialized compiler hints.
📋 Practical Task
Implement a Non-Null Guard for Order Processing
You are building an e-commerce checkout system. You have a OrderRequest data class where the shippingAddress is optional. You've written a helper function called isReadyForShipping that checks if the address is present and not empty.
Currently, the code below fails to compile because the compiler doesn't know that a true return from isReadyForShipping means the address is not null. Your task is to implement a Contract inside isReadyForShipping to enable the smart cast in the shipOrder function.
import kotlin.contracts.*
data class OrderRequest(val orderId: Int, val shippingAddress: String?)
fun isReadyForShipping(request: OrderRequest): Boolean {
// TODO: Add a contract here that implies request.shippingAddress != null if returns true
return !request.shippingAddress.isNullOrBlank()
}
fun shipOrder(request: OrderRequest) {
if (isReadyForShipping(request)) {
// This line currently causes a compiler error:
// Smart cast to 'String' is impossible
println("Shipping order ${request.orderId} to ${request.shippingAddress.uppercase()}")
} else {
println("Order ${request.orderId} is missing an address.")
}
}
fun main() {
val validOrder = OrderRequest(101, "123 Kotlin Lane")
val invalidOrder = OrderRequest(102, null)
shipOrder(validOrder)
shipOrder(invalidOrder)
}There are no comments for now.