Created
September 6, 2017 22:42
-
-
Save MaximilianoFelice/2399538a0c8d918ec46a009f01bdea12 to your computer and use it in GitHub Desktop.
[Medium] [Code] Builder Pattern in Scala with Phantom Types
This file contains hidden or 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
class Chef[Pizza <: Chef.Pizza](ingredients: Seq[String]) { | |
import Chef.Pizza._ | |
def addCheese(cheeseType: String): Chef[Pizza with Cheese] = new Chef(ingredients :+ cheeseType) | |
def addTopping(toppingType: String): Chef[Pizza with Topping] = new Chef(ingredients :+ toppingType) | |
def addDough: Chef[Pizza with Dough] = new Chef(ingredients :+ "dough") | |
def build(implicit ev: Pizza =:= FullPizza): Food = Food(ingredients) | |
} |
This file contains hidden or 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
object Chef { | |
sealed trait Pizza | |
object Pizza { | |
sealed trait EmptyPizza extends Pizza | |
sealed trait Cheese extends Pizza | |
sealed trait Topping extends Pizza | |
sealed trait Dough extends Pizza | |
type FullPizza = EmptyPizza with Cheese with Topping with Dough | |
} | |
} |
This file contains hidden or 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
case class Chef { | |
... | |
def build: Food = | |
if (hasDoughCheeseAndToppings(ingredients)) Food(ingredients) | |
else throw new FoodBuildingException("You tried to build a pizza without enough ingredients") | |
} |
This file contains hidden or 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
scala> new Chef().addDough.build | |
<console>:18: error: Cannot prove that Chef.Pizza.EmptyPizza with Chef.Pizza.Dough =:= Chef.Pizza.FullPizza. |
This file contains hidden or 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
scala> new Chef() | |
.addCheese("mozzarella") | |
.addDough | |
.addTopping("olives") | |
.build | |
res1: Food = Food(List(mozzarella, dough, olives)) |
This file contains hidden or 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
case class Door[State <: DoorState](){ | |
def open(implicit ev: State =:= Closed) = Door[Open]() | |
def close(implicit ev: State =:= Open) = Door[Closed]() | |
} |
This file contains hidden or 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
trait DoorState | |
case class Open() extends DoorState | |
case class Closed() extends DoorState | |
case class Door(state: DoorState) { | |
def open = state match { | |
case _: Open => throw new DoorStateException("You cannot open a door thats already open") | |
case _ => Door(Open()) | |
} | |
def close = state match { | |
case _: Closed => throw new DoorStateException("You cannot close a door thats already closed") | |
case _ => Door(Closed()) | |
} | |
} |
This file contains hidden or 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
scala> Door[Open]().open | |
<console>:17: error: Cannot prove that Open =:= Closed. |
This file contains hidden or 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
sealed trait DoorState | |
sealed trait Open extends DoorState | |
sealed trait Closed extends DoorState |
This file contains hidden or 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
def open(implicit ev: State =:= Closed) = Door[Open]() |
This file contains hidden or 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
case class Food(ingredients: Seq[String]) |
This file contains hidden or 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
implicit val context: Context = ??? | |
def methodThatRequiresContext(str: String)(implicit context: Context) = ??? | |
methodThatRequiresContext("foo") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment