The Problem with Defensive Boilerplate
In most programming languages, defensive coding involves a lot of repetitive if-statements. You check if a parameter is null, if a number is positive, or if a list is empty before proceeding. In Kotlin, while you can still use the traditional if-else approach, there is a much cleaner way to enforce these rules: Precondition Functions.
Kotlin provides a set of standard library functions designed to validate arguments and state. These functions make your intent clear and automatically throw the correct exception types, saving you from writing manual throw statements.
Validating Arguments with require()
The most common precondition is require(). You use this when you want to ensure that a value passed into a function meets specific criteria. If the condition is false, Kotlin throws an IllegalArgumentException.
fun setPlayerAge(age: Int) {
require(age >= 18) { "Player must be at least 18 years old. Provided: $age" }
// Proceed with logic
println("Age set to $age")
}In this example, the block inside the curly braces is a lazy-evaluated message. It only runs if the condition fails, which is better for performance if your error message involves complex string formatting.
Checking Internal State with check()
While require() is for external inputs, check() is for internal state. Use it when your code depends on an object being in a specific configuration before an action happens. If the condition is false, it throws an IllegalStateException.
class WaterHeater {
var isPluggedIn = false
fun activate() {
check(isPluggedIn) { "Cannot activate heater: Device is not plugged in." }
println("Heating water...")
}
}This distinction is important for debugging. When you see an IllegalStateException, you know the bug is likely inside your class logic, whereas an IllegalArgumentException points to the caller passing bad data.
Handling Unreachable Code with error()
Sometimes you reach a point in your code that should be theoretically impossible to hit. Instead of returning a null or a dummy value, use the error() function. It immediately throws an IllegalStateException with your message.
fun getDirection(input: String): String {
return when(input) {
"N" -> "North"
"S" -> "South"
else -> error("Unexpected direction input: $input")
}
}Why This Matters
Using these functions makes your code more "idiomatic." It moves the validation logic to the very top of your functions, acting as a clear contract for anyone reading your code. It also works perfectly with Kotlin's smart-casting. For example, if you use require(value != null), Kotlin is smart enough to treat value as non-null for the rest of that function scope. Stop nesting your logic inside if-blocks and start using preconditions to fail fast and keep your codebase clean.

