I have problem with Kotlin nullability and I'm wondering am I able to resolve it with contracts.
For such Java
interface: interface Action<T>{ void execute(T param); }
there is two extensions:
fun <T, R> Action<T>.map(mapper:(R)->T): Action<R> {
return Action{ execute(mapper(it)) }
}
and
fun <T> Action<T>.ifNotNull(): Action<T> {
return Action { if(it != null) execute(it) }
}
There is also a generic model with nullable data:
class Model<T>(val data: T?)
Now I have created function which take Action
interface as argument. Case is to execute action argument only when param != null
, so it looks like below:
fun <T> callback(model: Model<T>, action: Action<T>){
action
.map{ it.getData() } //compilation error: getData return T? when action require T
.ifNotNull() //execute only when data!=null
.execute(model)
}
So now, is there any option to use Kotlin contract to ensure compiler that action
will not execute with null parameter?
ModelAction
in your own answer simply provides the correct signature for ifNotNull()
:
fun <T> Action<T>.ifNotNull(): Action<T?> {
return Action { if(it != null) execute(it) }
}
Then you've got the order of operations wrong:
fun <T> callback(model: Model<T>, action: Action<T>){
action
.ifNotNull() // Action<T?>
.map { model: Model<T> -> model.data } // Action<Model<T>>
.execute(model)
}
Note that the compiler won't be able to infer R
for this map
usage. You could also write it as
fun <T> modelAction(action: Action<T>): Action<Model<T>> {
return action
.ifNotNull()
.map { it.data }
}
As a side note, the argument is the "wrong way around" for map
; such functions are more commonly called contramap
.