Hi, does anyone know why the `!!` is necessary in ...
# getting-started
m
Hi, does anyone know why the
!!
is necessary in the second branch of the
when
expression in this code? Isn’t there enough information for a smart cast to a non-nullable type?
Copy code
fun checkSomething(old: Something?, new: Something?): Something = when {
    old == null && new == null -> throw IllegalArgumentException("Both old and new arguments are null")
    old == null -> new!!
    new == null -> old
    else -> old
}
v
Theoretically, for a human brain, probably. But the Kotlin compiler can probably not cover all possible cases a human brain can handle. 😄 Maybe somewhen in the future. 🤷‍♂️
e
for this, if you change the order, then smart-casting will work
Copy code
when {
    old != null -> old
    new != null -> new
    else -> throw IllegalArgumentException("Both old and new arguments are null")
}
or of course simply
Copy code
requireNotNull(old ?: new)
perhaps your real use case is more complex?
m
Yeah, this is just a simple example. I can rearrange the conditions like this
Copy code
fun checkSomething(old: Something?, new: Something?): Something = when {
    old != null && new != null -> doSomething(old, new) // both smart casted as not nullable
    new != null -> doAnotherThing(new) // smart casted as not nullable
    old != null -> doAnotherThing(old) // smart casted as not nullable
    else -> throw IllegalArgumentException("Both old and new arguments are null")
}
but I’m surprised that the original code doesn’t work
s
I wonder if it's something that'll be improved by https://youtrack.jetbrains.com/issue/KT-63696
m
Yeah, while looking through the related issues, I found this one, which I think is more specific to what I was referring to 👍
as I mentioned, it’s not a major issue since I can reorder the conditions to enforce the smart cast, but it would be a nice feature to have
c
I think its more about the order logical expressions are evaluated. if the first term evaluates to
false
the second one is not going to be evaluated. so in your initial example with the
&&
if
old == null
the compiler cannot say anything about the value of
new
. example with a basic if expression. https://pl.kotl.in/5M83m7RwW
m
ok, that’s a very good point
v
Why can it not? The compiler could know that if the first path is taken both are
null
and that if the second path is taken only
old
is
null
as otherwise the first path would have been taken. But I still think it is just not aware as that needs interpretation skills that are trivial for human but not for the compiler unless explicitly told. 🤷‍♂️
I did not include the start script creator task as that project is started using Docker, but it would just be registering and wiring one additional task