small stdlib proposals to improve smart-casting co...
# stdlib
l
small stdlib proposals to improve smart-casting concerning nullability: we need a way to do
if(foo != null)
for multiple values and collection contents. Proposal part one add a
ifNotNull
function that takes vararg arguments of type
Any?
. given
Copy code
val a: Int? = 1
val b: String? = null
val c: Boolean? = false
this would allow to replace this:
Copy code
if (a != null && b != null && c != null) {
    println("$a, $b, $c")
}
with this:
Copy code
ifNotNull(a, b, c) {
    println("$a, $b, $c")
}
which imo is a lot more readable, and also easier to type. (small note/question: would these checks - if the function was just implemented in terms of contracts and the if-statement - short-circuit, like they do with the if-statement?) proposal part two higher-order-functions on collections should do smart-casting. (I guess this should be doable via contracts?) given
Copy code
fun useList(nums: List<Int>) = println(nums)
val foo: List<Int?> = listOf(12, 13, null, 14)
this would allow to do something like this:
Copy code
if (foo.all { it != null } ) {
	useList(foo)
}
currently, afaik, this check is not possible with compiler-guarantees, as there is no
Collection<T>.hasNoNulls()
check. there are some simmilar functions, but nothing that actually does this. there is -
Iterable<T?>.requireNoNulls()
- the most simmilar, but this throws exceptions and isn't as general as making
all
and
any
-calls smart-cast -
Iterable<T?>.filterNotNull()
- could be currently used in combination with the all-check to "simulate" a smart-casting all, but as it just filters out the null-values, this could to easily be broken if someone isn't careful when modifiying the preceding if-statement.
k
You can't really implement this in the stdlib yet, the closest you could get is having lots of overloads for all possible arguments counts:
Copy code
fun notNull(a: Any?, b: Any?, c: Any?): Boolean {
    contract { returns(true) implies (a != null && b != null && c != null) }
    return a != null && b != null && c != null
}
l
i'm not too confident with my knowledge about the contract-API, but couldn't you do it via vararg, and then do the checks via .all or something, and then specify in the contract that
returns(true) implies (args is Array<T>)
(where args is
vararg args: T?
? or why would this not work?
n
the real problem with `ifNotNull`(IMHO better named `noneNull`is that it evaluates all parameters first. Thus,
noneNull(a, b, b.c)
will not work. You would have to use `noneNull(a, b?.c)`instead but in my experience (I tried that) this leads to more problems than it solves
l
thats a valid concern,... so this would need to be implemented on a language level to allow for short-circuiting and such, correct?
👌 1