Does anyone know why I lose the smart cast to non-...
# announcements
d
Does anyone know why I lose the smart cast to non-null in for loop?
Copy code
data class Testing(val test: Int = 5)
var test: Testing? = null
if (test == null) test = Testing(3)
test.test // works
test = test.copy() // works
for (i in (1..10)) {
  test = test.copy() // complains about test being Testing?
}
d
Does seem like a bug. I assume what's going on is that since you re-assign
test
before the for-loop it invalidates any smart-casting information gathered before that point from then on, but fails to consider the actual type being assigned to
test
.
o
Please submit an issue to kotl.in/issue
a
Note:``` var test: Testing? = Testing(3) test = test.copy() // not happy either ```
d
@diesieben07 With the test = test.copy() before for loop? Same issue even if that is removed, was just showing that it worked with that outside/before for loop.
d
You are still re-assigning
test
inside the loop
If you have
val foo = test.copy()
in the loop, it works fine.
d
Ah, yes, I thought you were just pointing out the reassignment outside the loop.
a
There are limits to what static analysis can do, particularly in loops. I guess tracking a changing value on the same line it just gives up and sides with caution.
d
So would recommendation be to just use !!? ie test = test!!.copy()
a
Copy code
var test: Testing? = Testing(3)
test = test.copy() // not happy either
This case seems like something it could workout, but it's also like, why would anyone do this? Who would it help. Your case is similar, why do you need nullability?
d
My recommendation would be to show your actual code. Usually you really don't need `var`s. I have written thousands of lines of Kotlin and it basically never happens 😄
☝️ 1
a
Copy code
data class Testing(val test: Int = 5)
var test: Testing = Testing(3)
test.test // works
test = test.copy() // works
for (i in (1..10)) {
  test = test.copy() // works
}
Or use a function:``` data class Testing(val test: Int = 5) fun ny() { var test: Testing? = null if (test == null) test = Testing(3) test.test // works test = test.copy() // works method(test) } private fun method(test: Testing) { var test1 = test for (i in (1..10)) { test1 = test1.copy() // works } } ```
or a local var outside loop:
Copy code
data class Testing(val test: Int = 5)
    var test: Testing? = null
    if (test == null) test = Testing(3)
    test.test // works
    var foo = test.copy() // works
    for (i in (1..10)) {
        foo = foo.copy() // works
    }
    test = foo
Basically there are many ways to avoid
!!
. I'd never recommend it.
!!
is a smell.
☝️ 1
d
I dumbed down the code, but a more realistic dumbed view of code would be:
Copy code
...
val mapOfThings: Map<a, Thing?> = networkCallToGetThings()
for (a in b) { // b is List<a>
    var thing = mapOfThings[a]
    // do some logic with thing if it exists
    if (thing == null) thing = Thing(...)
    for (c in a.listOfC) {
        // bunch of logic using thing, including updating some properties with
        thing = thing.copy(...)
        // use updated thing
    }
}
...
d
Can't you use
mapOfThings.getOrPut(a) { Thing(...) }
?
d
I agree breaking out the logic would be best.. but constrained by a requirement of not refactoring/touching as little as possible right now. So was simply curious why it wasn’t still smart casted in the for loop.
@takeda The logic for the if (thing == null) is doing different things depending on if thing is null or exists
The logic before the if*
As in it needs to be nullable until the if check
d
How about:
Copy code
val thing = mapOfThings[a]?.let { thing -> 
// do stuff with thing if it exists
} ?: Thing(...)