https://kotlinlang.org logo
#getting-started
Title
# getting-started
k

Klitos Kyriacou

09/20/2023, 3:53 PM
Is there a plan in the roadmap to make the compiler know that
b
is not null in the following and doesn't require
!!
?
Copy code
if (a != null || b != null) {
        if (a == null) {
            val c: Any = b!!
        }
    }
c

Casey Brooks

09/20/2023, 4:00 PM
The logic behind why it’s not working is a bit weird, but the first if-statement would short-circuit if a is non-null and never evaluate the
b != null
expression, so within that block the compiler doesn’t really have any hard facts about
b
within that scope. Doing
if (a == null && b != null)
instead does give you the smart-cast, and it also removes the extra if-statement.
k

Klitos Kyriacou

09/20/2023, 4:16 PM
Thanks, that's interesting. I can't remove the extra if-statement because the actual structure I was working with was more like:
Copy code
val a = something...
    val b = something else...
    if (a != null || b != null) {
        // some code...
        if (a == null) {
            // do something with the obviously not null b
        }
        if (b == null) {
            // do something with the obviously not null a
        }
        // some more code...
    }
r

Ruckus

09/20/2023, 4:20 PM
@Casey Brooks Are you sure about that? The short circuiting happens at runtime, so saying the compiler has no information about
b
seems wrong. The compiler will see the entire expression, and absolutely should be able to infer the truthiness, regardless of what could happen at runtime.
There's no reason the compiler couldn't determine "If
a == null
, this expression didn't short circuit". It's just a matter of complexity of the static analysis.
c

Casey Brooks

09/20/2023, 4:25 PM
Hmm, I guess you’re right. Either way, though, nested if-statements can be rewritten in a way that keeps them all as a single flat chain of blocks, which is usually much easier to read. Nesting ifs inside ifs quickly gets very difficult to read and trace the logic, especially as the number of variables increases. A when statement like this can be a good way to model the individual conditions of complex logic:
Copy code
when {
    a != null && b == null -> { /* only a is non null */ }
    a == null && b != null -> { /* only b is non null */ }
    a != null && b != null -> { /* a and b are both non null */ }
    a == null && b == null -> { /* a and b are both null */ }
}
r

Ruckus

09/20/2023, 4:29 PM
I definitely agree on that front, though depending on the use case (doesn't appear to apply here, but something I've run into), when
a
and/or
b
are expressions and not just variables, you either need to extract them to variables or repeat the expressions multiple times, which can sometimes negatively affect readability or scoping as much as the flattening improved it. And that assumes there isn't interspersed logic around the various checks like there is here.
@Klitos Kyriacou It could be worth looking into extracting your
// some code...
and
// some more code...
chunks out to separate functions, that could then be called in the flattened blocks that @Casey Brooks showed. That could help reduce duplication while still making the logic clear.
👍 1
d

dmitriy.novozhilov

09/20/2023, 7:38 PM
Actually I think it's possible to add such smartcasts K2 data flow engine smart enough to operate such constructions @Klitos Kyriacou could you please file a feature request to youtrack?
k

Klitos Kyriacou

09/24/2023, 1:59 PM