Created
September 7, 2009 09:30
-
-
Save jrudolph/182249 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
// This code is based on an idea of Rafael de F. Ferreira and was implemented as a response to | |
// Jim McBeath's blog post http://jim-mcbeath.blogspot.com/2009/09/type-safe-builder-in-scala-part-2.html | |
// 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] | |
(brand:HAS_BRAND | |
,mode:HAS_MODE | |
,isDouble:HAS_DOUBLE | |
) { | |
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] = | |
Builder(Some(brand),b.mode,b.isDouble) | |
def withMode[B<:Option[String],D<:Option[Boolean]](mode:Preparation)(b:Builder[B,None,D]):Builder[B,Some[Preparation],D] = | |
Builder(b.brand,Some(mode),b.isDouble) | |
def isDouble[B<:Option[String],M<:Option[Preparation]](isDouble:Boolean)(b:Builder[B,M,None]):Builder[B,M,Some[Boolean]] = | |
Builder(b.brand,b.mode,Some(isDouble)) | |
def build(b:Builder[Some[String],Some[Preparation],Some[Boolean]]):OrderOfScotch = | |
OrderOfScotch(b.brand.get,b.mode.get,b.isDouble.get) | |
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 | |
x | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment