Skip to content

Instantly share code, notes, and snippets.

@dragisak
Last active August 29, 2015 14:04
Show Gist options
  • Save dragisak/93bc4e8944d58975b14e to your computer and use it in GitHub Desktop.
Save dragisak/93bc4e8944d58975b14e to your computer and use it in GitHub Desktop.
Safe builder pattern in Scala
case class Address(street: String, state: String, zip: Int)
object AddressBuilder {
sealed trait Prop
sealed trait OK extends Prop
sealed trait Missing extends Prop
private[AddressBuilder] case class AddressBuilder[A <: Prop, B <: Prop, C <: Prop](
street : Option[String] = None,
state : Option[String] = None,
zip : Option[Int] = None
) {
def street(s: String) : AddressBuilder[OK, B, C] = copy(street = Some(s))
def state(s: String) : AddressBuilder[A, OK, C] = copy(state = Some(s))
def zip(z: Int) : AddressBuilder[A, B, OK] = copy(zip = Some(z))
}
val address :AddressBuilder[Missing, Missing, Missing] = AddressBuilder()
trait OkToBuild {
def create: Address
}
implicit def okToBuild(b: AddressBuilder[OK, OK, OK]): OkToBuild =
new OkToBuild {
override def create = Address(b.street.get, b.state.get, b.zip.get)
}
}
object Example {
import AddressBuilder._
val a = address street "75 Federal" state "CA" zip 94107 create
val b = address zip 94107 street "75 Federal" state "CA" create
// Does not compile
// val b = address street "75 Federal" state "CA" create
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment