Home > Enterprise >  Kotlin compiler reports unused expression in constructor for builder taking vararg lambdas
Kotlin compiler reports unused expression in constructor for builder taking vararg lambdas

Time:07-23

We have a relatively simple builder pattern we use for test data generator in Kotlin.

The builders follow the pattern:

class ThingBuilder private constructor(
    var param1: Int = 1,
    var param2: Boolean = true
) {
    private constructor(vararg inits: ThingBuilder.(ThingBuilder) -> Unit) : this() {
        inits.forEach { it(this) }
    }

    fun build(): Thing {
        return Thing(
            param1,
            param2
        )
    }

    companion object {
        fun asDefaultCase(init: ThingBuilder.(ThingBuilder) -> Unit = {}): ThingBuilder {
            return ThingBuilder(init)
        }

        fun asSomethingElseCase(init: ThingBuilder.(ThingBuilder) -> Unit = {}): ThingBuilder {
            return ThingBuilder({ b -> b.param2 = false }, init)
        }
    }
}

Here the Kotlin compiler reports a warning:

The expression is unused

which references the line:

inits.forEach { it(this) }

I've tried turning that into an Array<T> rather than varags but same warning occurs.

What would be the more correct way to make this structure where the consumers can pass in lambdas to configure the builder data?

(for reference, the code works correctly and the loop functions as expected)

CodePudding user response:

This seems to be a rather old bug KT-21282 False positive UNUSED_EXPRESSION compiler warning with object and lambda with receiver / extension function type.

The fix is simple - just specify the explicit receiver and do this.it(this). I also don't see why you would need to pass this as both the receiver and the formal parameter to the block. I would just do this instead:

private constructor(vararg inits: ThingBuilder.() -> Unit) : this() {
    inits.forEach { this.it() }
}

or:

private constructor(vararg inits: ThingBuilder.() -> Unit) : this() {
    inits.forEach { it(this) }
}

Then you don't even need to write the b parameter in asSomethingElseCase:

fun asSomethingElseCase(init: ThingBuilder.() -> Unit = {}): ThingBuilder {
    return ThingBuilder({ param2 = false }, init)
}
  • Related