Last active
September 6, 2017 19:50
-
-
Save BrianLondon/57954d01130c965d17404f31db4ad3b3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile time validated builder pattern using type level programming | |
sealed trait Fur | |
case object Short extends Fur | |
case object Long extends Fur | |
case object Curly extends Fur | |
case class Dog(name: String, age: Int, fur: Fur) | |
sealed trait Bool | |
trait True extends Bool | |
trait False extends Bool | |
class DogBuilder[HasName <: Bool, HasAge <: Bool, HasFur <: Bool]( | |
val name: Option[String], | |
val age: Option[Int], | |
val fur: Option[Fur]) | |
object DogBuilder { | |
def apply() = new DogBuilder[False, False, False](None, None, None) | |
implicit def withNameBuilder[HasAge <: Bool, HasFur <: Bool](db: DogBuilder[False, HasAge, HasFur]) = new { | |
def withName(name: String) = new DogBuilder[True, HasAge, HasFur](Some(name), db.age, db.fur) | |
} | |
implicit def withAgeBuilder[HasName <: Bool, HasFur <: Bool](db: DogBuilder[HasName, False, HasFur]) = new { | |
def withAge(age: Int) = new DogBuilder[HasName, True, HasFur](db.name, Some(age), db.fur) | |
} | |
implicit def withFurBuilder[HasName <: Bool, HasAge <: Bool](db: DogBuilder[HasName, HasAge, False]) = new { | |
def withFur(fur: Fur) = new DogBuilder[HasName, HasAge, True](db.name, db.age, Some(fur)) | |
} | |
implicit def realizeBuilder(db: DogBuilder[True, True, True]) = new { | |
def toDog: Dog = Dog(db.name.get, db.age.get, db.fur.get) | |
} | |
} | |
/* Example User */ | |
val fidoBuilder = DogBuilder() | |
val fido = fidoBuilder.withAge(3).withFur(Short).withName("fido").toDog | |
val namelessBuilder = DogBuilder() | |
val nameless = namelessBuilder.withAge(7).withFur(Curly).toDog // this won't compile because name is missing |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment