In Kotlin, a contract is a way to define the behavior of a function in terms of its inputs and outputs. Specifically, a contract consists of a set of conditions that the function guarantees to be true before and after it is called. This allows the compiler and runtime to verify that the function behaves correctly and can provide developers with additional safety guarantees.
For example, let us consider a function that divides two integers:
fun divide(a: Int, b: Int): Int {
return a / b
}
In this function, there is no guarantee that the division will not result in an exception. However, with the use of contracts, we can add a precondition that ensures the second parameter ‘b‘ is not zero:
@OptIn(ExperimentalContracts::class)
fun divide(a: Int, b: Int): Int {
contract {
requires(b != 0)
}
return a / b
}
By using a contract, we are making sure that the ‘divide‘ function will only be called with valid values, thus ensuring that the function behaves predictably and safely.
Another example is the ‘checkNotNull‘ function, which ensures that a given object is not ‘null‘:
@OptIn(ExperimentalContracts::class)
public inline fun <T : Any> checkNotNull(
value: T?,
lazyMessage: () -> Any = { "Required value was null." }
): T {
contract {
returnsNotNull() // Ensures that the return value is not null
}
if (value == null) {
throw NullPointerException(lazyMessage().toString())
}
return value
}
The contract for ‘checkNotNull‘ ensures that the method will return a non-null value. In addition to improving predictability and safety, contracts can also be used by the compiler to optimize code.
In conclusion, contracts in Kotlin provide an additional layer of safety and predictability for functions, by allowing developers to specify preconditions and postconditions that must be met. This helps to catch bugs before they happen and makes functions easier to reason about.