Smart casts on nested null checks?

Hi,

I’m not sure what to title this post. I don’t think the type system can help me here, and I probably just need to use !!, but I wanted to check.

Say I have a type like this:

class Thing {
    var txnID: String
    var expiresDate: Instant? 
    ...
}

I have a list of them and I filter in a way that only gets elements with non-null expiresDate:

val things: List<Thing> = ...
val nonExpired = things.filter { it.expiresDate != null && now.isBefore(it.expiresDate) }
for (thing in nonExpired) {
    useTheDate(thing.expiresDate!!)
}

In a way, I’ve proved that I don’t need the !!, but I guess if I want to use the type system to encode that, I’d need another type (named ??) that would look like Thing expect have a non-nullable expiresDate.

There’s not some other slick way, is there?

Rob

There’s actually nothing in the List interface (except for comments) that says the things you’re iterating through are the same things you just passed with filter, so there’s no way for the compiler to know that thing.expiresDate is non-null.

You just know this, because you know how lists are supposed to work.

But, you can always do this:

val nonExpiredDates = things.mapNotNull { thing ->
   thing.expiresDate?.takeIf {now.isBefore(it)}
}
for (date in nonExpired) {
    useTheDate(date)
}

Or this:

val nonExpired = things.filter { it.expiresDate != null && now.isBefore(it.expiresDate) }
for (thing in nonExpired) {
    thing.expiresDate?.let{ useTheDate(it) }
}

I usually like to recheck instead of using !!, because !! can cause NPEs when you move the code or change other things that invalidate your unwritten proof that the thing is non-null.