Type inference failure

I’m trying to define a new function to capture this common pattern:

.apply {
    if (condition) {
        performAction()
    }
}

Here is the function definition:

inline fun <T> T.applyIf(condition: Boolean, block: T.() -> Unit): T {
    if (condition) block()

    return this
}

This is usually used in a chain, as a hypothetical example, lets say we have a builder:

val result = PersonBuilder()
    .name("Bob")
    .apply {
        if (spouse != null) {
            spouseAge(spouse.age)
        }
    }
   .build()

So with the new function, I would like to use it like this:

val result = PersonBuilder()
    .name("Bob")
    .applyIf(spouse != null) {
        spouseAge(spouse.age)
    }
   .build()

but this doesn’t work because spouse is not smart cast into a non-null type.

I was hoping to be able to add a contract to make the type inference work but I didn’t see anything that would help in this scenario.

Any suggestions? Can we get a new contract to handle this type of scenario?

Looks like contracts can’t help here. A contract - returns() implies in particular - claims some condition that must be true after the function call has completed. But in applyIf(spouse != null) { spouseAge(spouse.age) } the spouse.age can be (and actually is) calculated during the call execution.

For new type of contract please file a feature request into the bugtracker: https://youtrack.jetbrains.com/issues/KT
I don’t know the final developers’ answer, but they will consider it.

Thanks, I filed this feature request:

https://youtrack.jetbrains.com/issue/KT-32993