Create a gist now

Instantly share code, notes, and snippets.

// This code is based on an idea of Rafael de F. Ferreira and was implemented as a response to
// Jim McBeath's blog post
// Everyone is free to use, modify, republish, sell or give away this work without prior consent from anybody.
object Scotch {
sealed abstract class Preparation
case object Neat extends Preparation
case object OnTheRocks extends Preparation
case object WithWater extends Preparation
case class OrderOfScotch private[Scotch](val brand:String, val mode:Preparation, val isDouble:Boolean)
trait Option[+X]
case class Some[+X](x:X) extends Option[X]{
def get:X = x
trait None extends Option[Nothing] // this differs in the original implementation
case object None extends None
case class Builder[HAS_BRAND<:Option[String],HAS_MODE<:Option[Preparation],HAS_DOUBLE<:Option[Boolean]] private[Scotch]
) {
def ~[X](f:Builder[HAS_BRAND,HAS_MODE,HAS_DOUBLE] => X):X = f(this)
def withBrand[M<:Option[Preparation],D<:Option[Boolean]](brand:String)(b:Builder[None,M,D]):Builder[Some[String],M,D] =
def withMode[B<:Option[String],D<:Option[Boolean]](mode:Preparation)(b:Builder[B,None,D]):Builder[B,Some[Preparation],D] =
def isDouble[B<:Option[String],M<:Option[Preparation]](isDouble:Boolean)(b:Builder[B,M,None]):Builder[B,M,Some[Boolean]] =
def build(b:Builder[Some[String],Some[Preparation],Some[Boolean]]):OrderOfScotch =
def builder:Builder[None,None,None] = Builder(None,None,None)
def test {
val x:OrderOfScotch = builder ~ isDouble(true) ~ withMode(Neat) ~ withBrand("Blubber") ~ build
// builder ~ isDouble(true) ~ withMode(Neat) ~ build // fails
// builder ~ isDouble(true) ~ withMode(Neat) ~ withBrand("Blubber") ~ withBrand("Blubber") ~ build // fails
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment