Reputation: 16043
What I mean is following.
Consider this code:
// Can be a Long or null
val data1= param1.toLongOrNull()
val data2= param2.toLongOrNull()
val dataN= paramN.toLongOrNull()
// Proceed with the action if ALL of the data are not nulls
if(notNull(data1, data2, dataN)){
// do something with data1,2,N
}
notNull()
is a utility function that accepts a list of variable arguments.
Returns true if all of the arguments are not nulls.
fun <T> notNull(vararg elements: T): Boolean {
elements.forEach {
if (it == null) {
return false
}
}
return true
}
The issue I am having is that Kotlin does not know that inside the if
block, the data1,2,N cannot be null. As a result, this fails to compile:
if(notNull(data1, data2, dataN)){
data1 + data2 + dataN
// Fail: Required Long, Found Long?
// Operator + not allowed on nullable receiver.
}
On the other hand, if the variables are explicitly checked against null, then Kotlin knows this is fine and does not complain.
if(data1!=null && data2!=null && dataN!=null){
data1 + data2 + dataN
}
It would be nice to "configure" the notNull
method in such way, so that Kotlin knows that once it returns true, any of the passed parameters cannot be null inside the block.
Is this possible?
Upvotes: 4
Views: 1214
Reputation: 9919
Obviously multiple ways to skin a cat, but you could do something like this :
inline fun <T> doIfNotNull(elements: Array<T?>, block : (Array<T>) -> Unit) {
val validElements = arrayListOf<T>()
for (i in elements) {
if (i == null) return
validElements.add(i)
}
block.invoke(validElements.toArray(elements))
}
Using with varargs (has to be last parameter, making the receiver function first arg, which doesn't feel as nice);
inline fun <T> doIfNotNull(block : (Array<T>) -> Unit, vararg elements : T?) {
val validElements = arrayListOf<T>()
for (i in elements) {
if (i == null) return
validElements.add(i)
}
block.invoke(validElements.toArray(elements))
}
Example :
fun test() {
val elements = arrayOf(1L, 2L, null)
doIfNotNull(elements, {
it.sum()
})
}
Upvotes: 2