Using scope functions is one way to solve this but results in code that is hard to read imo. If you stick to the builder pattern, the simplest solution would be to modify the builder to accept Null values:
class Builder {
private var type1: Type1 = <default>
private var type2: Type2 = <defaul>
fun setType1(type: Type1?): Builder {
if (type != null) this.type1 = type
return this
}
fun setType2(type: Type2?): Builder {
if (type != null) this.type2 = type
return this
}
}
That way you can keep:
class1.newBuilder()
.setType1(var1)
.setType2(var2)
.build()
To communicate the fact that the values won't be set if they are Null, change the name of the setters to e.g. setTypeIfNotNull.
With Kotlin the builder pattern is kind of obsolete (unless you create a DSL) because you can use a constructor with default and named arguments instead, something like:
class Request(val type1: Type1 = <default>, val type2: Type2 = <default>)
Then you can do:
Request(
type1 = type1,
type2 = type2,
)
Now this doesn't cover the Null case but you can use this to accept null values:
companion object {
public operator fun invoke(type1: Type1, type2: Type2? = null) = Request(type1, type2 ?: <default value>)
}
The reason why there's a companion object instead of a constructor is explained here: Is there a way to use the default value on a non-optional parameter when null is passed?.