https://kotlinlang.org logo
#getting-started
Title
# getting-started
d

Daniel Pitts

11/11/2023, 4:35 AM
Is there a way to allow builder type inference with a default value if the type isn't inferable? For example,
Copy code
interface Builder<T> {
   fun initialValue(value: T)
   fun otherMethodsThatWithoutT()
}

fun <T> build(block: Builder<T>.()->Unit) = 
   BuilderImpl<T>().apply(block)

val buildWithType = build { initialValue(0.0) } // T = Double
bal buildWithouType = build { } // Default T to Unit
m

Michael de Kaste

11/13/2023, 1:06 PM
default values for generic types isn't available, so your best bet would be to create a second function or value. best bet would be:
Copy code
val build = BuilderImpl<Unit>()
fun build() = BuilderImpl<Unit>()
d

Daniel Pitts

11/14/2023, 2:44 AM
I've tried having a second function, but then overload doesn't work.
Copy code
fun <S> sketch(build: SketchBuilder<S>.() -> Unit) {
    SketchBuilderImpl<S>().apply(build)
}

fun sketch(build: SketchBuilder<Unit>.() -> Unit) {
    SketchBuilderImpl<Unit>().apply(build)
}

fun makeSketches() {
    sketch {
        // `this` is SketchBuilder<Unit>
    }

    sketch {
        initialState("") // compiler error: type mismatch, expected Unit, got String
    }
    sketch<String> {
        // `this` is SketchBuilder<String>, but  annoying to have to put the type here
        initialState("")
    }
}
So, the user of my DSL will have to explicitly state its typeless, or explicitly state the type.
I think this is the next best approach:
Copy code
fun <S> sketch(build: SketchBuilder<S>.() -> Unit) {
    SketchBuilderImpl<S>().apply(build)
}

val SketchBuilder<Unit>.stateless get() = Unit

fun makeSketches() {
    sketch {
        stateless
        // `this` is SketchBuilder<Unit>
    }

    sketch {
        initialState("")
        // `this` is SketchBuilder<String>
    }
}