Skip to content

Instantly share code, notes, and snippets.

@breandan
Last active May 1, 2024 12:28
Show Gist options
  • Save breandan/d0d7c21bb7f78ef54c21ce6a6ac49b68 to your computer and use it in GitHub Desktop.
Save breandan/d0d7c21bb7f78ef54c21ce6a6ac49b68 to your computer and use it in GitHub Desktop.
Type safe builder pattern in Kotlin using Phantom Types (inspired by http://blog.rafaelferreira.net/2008/07/type-safe-builder-pattern-in-scala.html)
import Thing.*
fun main() {
val foo0: Thing = Thing.setB(2).setA(1).setC(3).setD(4).build()
println("foo0: $foo0")
val foo1: Thing = Thing.setA(1).setB(2).setC(3).setD(4).build()
println("foo1: $foo1")
val foo2: Thing = Thing.setC(3).setB(2).setA(1).setD(4).build()
println("foo2: $foo2")
// val foo3: Thing = Thing.setA(1).setB(2).setC(3).build() // Compile error
}
class Thing constructor(
private val a: Int,
private val b: Int,
private val c: Int,
private val d: Int
) {
abstract class OK
abstract class NO
companion object : ThingBuilder<NO, NO, NO, NO>()
override fun toString() = "a = $a, b = $b, c = $c, d = $d"
open class ThingBuilder<A, B, C, D> internal constructor(
internal var a: Int = 0,
internal var b: Int = 0,
internal var c: Int = 0,
internal var d: Int = 0
) {
fun setA(a: Int): ThingBuilder<OK, B, C, D> = ThingBuilder(a, b, c, d)
fun setB(b: Int): ThingBuilder<A, OK, C, D> = ThingBuilder(a, b, c, d)
fun setC(c: Int): ThingBuilder<A, B, OK, D> = ThingBuilder(a, b, c, d)
fun setD(d: Int): ThingBuilder<A, B, C, OK> = ThingBuilder(a, b, c, d)
}
}
fun ThingBuilder<OK, OK, OK, OK>.build() = Thing(a, b, c, d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment