SlideShare a Scribd company logo
Having a cake and eating it
too.
Introduction to Type classes (in Scala)
“The Story of
a Blackout”
In 4 acts
Act.1: “Loss & Grief”
503 Service Temporarily Unavailable
nginx
503 Service Temporarily Unavailable
nginx
The 5 Stages of Loss and Grief
The 5 Stages of Loss and Grief
1. Denial
The 5 Stages of Loss and Grief
1. Denial
2. Anger
The 5 Stages of Loss and Grief
1. Denial
2. Anger
3. Bargaining
The 5 Stages of Loss and Grief
1. Denial
2. Anger
3. Bargaining
4. Depression
The 5 Stages of Loss and Grief
1. Denial
2. Anger
3. Bargaining
4. Depression
5. Acceptance
Act.2: “The Mess”
auction
auctionify
auctionify.io
Domain & Feature Requests
Domain:
● Users place Orders in the auction system
Order
Domain & Feature Requests
Domain:
● Users place Orders in the auction system
● Orders can be:
○ General - contain list of Products
○ Complex - combined from two or more
other Orders
○ Cancelled - used to be fully fledged
Orders, but now are cancelled
Order
General Complex Cancelled
Domain & Feature Requests
Domain:
● Users place Orders in the auction system
● Orders can be:
○ General - contain list of Products
○ Complex - combined from two or more
other Orders
○ Cancelled - used to be fully fledged
Orders, but now are cancelled
● Products can be:
○ Basic - id & price
○ Discounted - wrapped Product &
discount
○ OutOfStock - used to be in warehouse, but
now gone (sorry)
Order
General Complex Cancelled
Product
Basic Discounter
Out of
Stock
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
sealed trait Order
case class GeneralOrder(products: List[Product]) extends Order
case object CancelledOrder extends Order
case class ComplexOrder(orders: List[Order]) extends Order
sealed trait Product
case class BasicProduct(id: Int, price: BigDecimal) extends Product
case class DiscountedProduct(product: Product,
discount: Double) extends Product
case object OutOfStock extends Product
sealed trait Order
case class GeneralOrder(products: List[Product]) extends Order
case object CancelledOrder extends Order
case class ComplexOrder(orders: List[Order]) extends Order
sealed trait Product
case class BasicProduct(id: Int, price: BigDecimal) extends Product
case class DiscountedProduct(product: Product,
discount: Double) extends Product
case object OutOfStock extends Product
sealed trait Order
case class GeneralOrder(products: List[Product]) extends Order
case object CancelledOrder extends Order
case class ComplexOrder(orders: List[Order]) extends Order
sealed trait Product
case class BasicProduct(id: Int, price: BigDecimal) extends Product
case class DiscountedProduct(product: Product,
discount: Double) extends Product
case object OutOfStock extends Product
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
[error] OrderTest.scala evaluate is not a member of jw.ComplexOrder
[error] order.evaluate should equal (BigDecimal("11.0"))
[error] ^
[error] one error found
Subtype Polymorphism
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
[error] OrderTest.scala evaluate is not a member of jw.ComplexOrder
[error] order.evaluate should equal (BigDecimal("11.0"))
[error] ^
[error] one error found
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
sealed trait Order
case class GeneralOrder(products: List[Product]) extends Order
case object CancelledOrder extends Order
case class ComplexOrder(orders: List[Order]) extends Order
sealed trait Product
case class BasicProduct(id: Int, price: BigDecimal) extends Product
case class DiscountedProduct(product: Product,
discount: Double) extends Product
case object OutOfStock extends Product
trait Evaluatable[T] { def evaluate: T }
sealed trait Order extends Evaluatable[BigDecimal]
case object CancelledOrder extends Order {
def evaluate: BigDecimal = BigDecimal("0.0")
}
case class ComplexOrder(orders: List[Order]) extends Order {
def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + o.evaluate
}
}
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + p.evaluate
}
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Order extends Evaluatable[BigDecimal]
case object CancelledOrder extends Order {
def evaluate: BigDecimal = BigDecimal("0.0")
}
case class ComplexOrder(orders: List[Order]) extends Order {
def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + o.evaluate
}
}
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + p.evaluate
}
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Order extends Evaluatable[BigDecimal]
case object CancelledOrder extends Order {
def evaluate: BigDecimal = BigDecimal("0.0")
}
case class ComplexOrder(orders: List[Order]) extends Order {
def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + o.evaluate
}
}
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + p.evaluate
}
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Order extends Evaluatable[BigDecimal]
case object CancelledOrder extends Order {
def evaluate: BigDecimal = BigDecimal("0.0")
}
case class ComplexOrder(orders: List[Order]) extends Order {
def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + o.evaluate
}
}
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + p.evaluate
}
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Order extends Evaluatable[BigDecimal]
case object CancelledOrder extends Order {
def evaluate: BigDecimal = BigDecimal("0.0")
}
case class ComplexOrder(orders: List[Order]) extends Order {
def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + o.evaluate
}
}
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + p.evaluate
}
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Product extends Evaluatable[BigDecimal]
case class BasicProduct(id: Int, price: BigDecimal) extends Product {
def evaluate: BigDecimal = price
}
case class DiscountedProduct(product: Product, discount: Double) extends Product {
def evaluate: BigDecimal = product.evaluate * (1 - discount)
}
case object OutOfStock extends Product {
def evaluate: BigDecimal = BigDecimal("0.0")
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Product extends Evaluatable[BigDecimal]
case class BasicProduct(id: Int, price: BigDecimal) extends Product {
def evaluate: BigDecimal = price
}
case class DiscountedProduct(product: Product, discount: Double) extends Product {
def evaluate: BigDecimal = product.evaluate * (1 - discount)
}
case object OutOfStock extends Product {
def evaluate: BigDecimal = BigDecimal("0.0")
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Product extends Evaluatable[BigDecimal]
case class BasicProduct(id: Int, price: BigDecimal) extends Product {
def evaluate: BigDecimal = price
}
case class DiscountedProduct(product: Product, discount: Double) extends Product {
def evaluate: BigDecimal = product.evaluate * (1 - discount)
}
case object OutOfStock extends Product {
def evaluate: BigDecimal = BigDecimal("0.0")
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Product extends Evaluatable[BigDecimal]
case class BasicProduct(id: Int, price: BigDecimal) extends Product {
def evaluate: BigDecimal = price
}
case class DiscountedProduct(product: Product, discount: Double) extends Product {
def evaluate: BigDecimal = product.evaluate * (1 - discount)
}
case object OutOfStock extends Product {
def evaluate: BigDecimal = BigDecimal("0.0")
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
test("should evaluate order") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = GeneralOrder(DiscountedProduct(
product = BasicProduct(11, BigDecimal("1")),
discount = 0.2) :: Nil)
val o3 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)
order.evaluate should equal (BigDecimal("11.0"))
}
[info] OrderTest:
[info] - should evaluate order
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
[error] OrderTest.scala average is not a member of jw.Order
[error] Order.average should equal (BigDecimal("5.0"))
[error] ^
[error] one error found
object Stat {
def mean(xs: Seq[BigDecimal]): BigDecimal = ???
}
object Stat {
def mean(xs: Seq[BigDecimal]): BigDecimal =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean(xs: Seq[BigDecimal]): BigDecimal =
xs.reduce(_ + _) / xs.size
}
AWESOME!
I just need it to work for
Doubles and Ints as
well! Can you make it
more generic? Thx!
object Stat {
def mean(xs: Seq[BigDecimal]): BigDecimal =
xs.reduce(_ + _) / xs.size
}
object Stat {
def mean(xs: Seq[Number]): Number =
xs.reduce(_ + _) / xs.size
}
object Stat {
def mean(xs: Seq[Number]): Number =
xs.reduce(_ + _) / xs.size
}
trait Number[A] {
def value: A
def +(other: Number[A]): Number[A]
def /(other: Number[A]): Number[A]
def /(other: Int): Number[A]
}
trait Number[A] {
def value: A
def +(other: Number[A]): Number[A]
def /(other: Number[A]): Number[A]
def /(other: Int): Number[A]
}
case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {
def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)
def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)
def /(other: Int) = BigDecimalNumber(value / other)
}
trait Number[A] {
def value: A
def +(other: Number[A]): Number[A]
def /(other: Number[A]): Number[A]
def /(other: Int): Number[A]
}
case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {
def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)
def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)
def /(other: Int) = BigDecimalNumber(value / other)
}
trait Number[A] {
def value: A
def +(other: Number[A]): Number[A]
def /(other: Number[A]): Number[A]
def /(other: Int): Number[A]
}
case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {
def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)
def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)
def /(other: Int) = BigDecimalNumber(value / other)
}
case class IntNumber(value: Int) extends Number[Int] {
def +(other: Number[Int]) = IntNumber(value + other.value)
def /(other: Number[Int]) = IntNumber(value / other.value)
def /(other: Int) = IntNumber(value / other)
}
trait Number[A] {
def value: A
def +(other: Number[A]): Number[A]
def /(other: Number[A]): Number[A]
def /(other: Int): Number[A]
}
case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {
def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)
def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)
def /(other: Int) = BigDecimalNumber(value / other)
}
case class IntNumber(value: Int) extends Number[Int] {
def +(other: Number[Int]) = IntNumber(value + other.value)
def /(other: Number[Int]) = IntNumber(value / other.value)
def /(other: Int) = IntNumber(value / other)
}
case class DoubleNumber(value: Double) extends Number[Double] {
def +(other: Number[Double]) = DoubleNumber(value + other.value)
def /(other: Number[Double]) = DoubleNumber(value / other.value)
def /(other: Int) = DoubleNumber(value / other)
}
object Stat {
def mean(xs: Seq[BigDecimal]): BigDecimal =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate)))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate)))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate)))
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value
}
test("should calculate average") {
val o1 = GeneralOrder(DiscountedProduct(product =
BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)
val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)
val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))
}
[info] OrderTest:
[info] - should evaluate order
[info] - should calculate average
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
[error] OrderTest.scala not found: value JsonSerializer
[error] JsonSerializer.write(order) should equal(expectedJson)
[error] ^
object JsonSerializer {
def write(order: Order): String = ...
}
I have few objects I also need to
serialize to JSON. Can you make
your code a bit more generic?
Thanks!!!
object JsonSerializer {
def write(order: Order): String = ...
}
object JsonSerializer {
def write(sth: ???): String = ...
}
object JsonSerializer {
def write(serializable: JsonSerializable) = ...
}
object JsonSerializer {
def write(serializable: JsonSerializable) = ...
}
trait JsonSerializable {
def toJson: JsonValue
}
object JsonSerializer {
def write(serializable: JsonSerializable) =
JsonWriter.write(serializable.toJson)
}
trait JsonSerializable {
def toJson: JsonValue
}
object JsonSerializer {
def write(serializable: JsonSerializable) =
JsonWriter.write(serializable.toJson)
}
trait JsonSerializable {
def toJson: JsonValue
}
sealed trait JsonValue
sealed trait JsonValue
case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue
case class JsonArray(elems: List[JsonValue]) extends JsonValue
case class JsonString(value: String) extends JsonValue
case class JsonNumber(value: BigDecimal) extends JsonValue
sealed trait JsonValue
case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue
case class JsonArray(elems: List[JsonValue]) extends JsonValue
case class JsonString(value: String) extends JsonValue
case class JsonNumber(value: BigDecimal) extends JsonValue
object JsonWriter {
def write(json: JsonValue): String =
sealed trait JsonValue
case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue
case class JsonArray(elems: List[JsonValue]) extends JsonValue
case class JsonString(value: String) extends JsonValue
case class JsonNumber(value: BigDecimal) extends JsonValue
object JsonWriter {
def write(json: JsonValue): String = json match {
case JsonObject(elems) =>
val entries = for {
(key, value) <- elems
} yield s""""$key: ${write(value)}""""
"{" + entries.mkString(", ") + "}"
case JsonArray(elems) => "[" + elems.map(write).mkString(", ") + "]"
case JsonString(value) => s""""$value""""
case JsonNumber(value) => value.toString
}
}
sealed trait JsonValue
case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue
case class JsonArray(elems: List[JsonValue]) extends JsonValue
case class JsonString(value: String) extends JsonValue
case class JsonNumber(value: BigDecimal) extends JsonValue
object JsonWriter {
def write(json: JsonValue): String = ...
}
sealed trait JsonValue
case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue
case class JsonArray(elems: List[JsonValue]) extends JsonValue
case class JsonString(value: String) extends JsonValue
case class JsonNumber(value: BigDecimal) extends JsonValue
object JsonWriter {
def write(json: JsonValue): String = ...
}
trait JsonSerializable {
def toJson: JsonValue
}
object JsonSerializer {
def write(serializable: JsonSerializable) =
JsonWriter.write(serializable.toJson)
}
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = ...
def toJson: JsonValue = JsonObject(Map(
"type" -> JsonString("general"),
"products" -> JsonArray(products.map(_.toJson))
))
}
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
case object CancelledOrder extends Order {
def evaluate: BigDecimal = ...
def toJson: JsonValue = JsonString("cancelled order")
}
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
case class ComplexOrder(orders: List[Order]) extends Order {
def evaluate: BigDecimal = ...
def toJson: JsonValue = JsonObject(Map(
"type" -> JsonString("complex"),
"orders" -> JsonArray(orders.map(_.toJson)))
)
}
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
case class BasicProduct(id: Int, price: BigDecimal) extends Product {
def evaluate: BigDecimal = ...
def toJson: JsonValue = JsonObject(Map(
"type" -> JsonString("basic"),
"id" -> JsonNumber(BigDecimal(id)),
"price" -> JsonNumber(price)
))
}
sealed trait Product extends Evaluatable[BigDecimal] with JsonSerializable
case class DiscountedProduct(product: Product, discount: Double) extends Product {
def evaluate: BigDecimal = ...
def toJson: JsonValue = JsonObject(Map(
"type" -> JsonString("discounted"),
"product" -> product.toJson,
"discount" -> JsonNumber(discount)
))
}
sealed trait Product extends Evaluatable[BigDecimal] with JsonSerializable
case object OutOfStock extends Product {
def evaluate: BigDecimal = ...
def toJson: JsonValue = JsonString("out of stock")
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
[info] OrderTest:
[info] - should evaluate order
[info] - should calculate average
[info] - should serialize to json
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Our goal:
● DRY principle
● Separation of concerns
● Epic decoupling
● Clean API
● Minimal Boilerplate
Act.3: “Re-inventing the
Wheel”
trait Number[A] {
def value: A
def +(other: Number[A]): Number[A]
def /(other: Number[A]): Number[A]
def /(other: Int): Number[A]
}
case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {
def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)
def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)
def /(other: Int) = BigDecimalNumber(value / other)
}
case class IntNumber(value: Int) extends Number[Int] {
def +(other: Number[Int]) = IntNumber(value + other.value)
def /(other: Number[Int]) = IntNumber(value / other.value)
def /(other: Int) = IntNumber(value / other)
}
case class DoubleNumber(value: Double) extends Number[Double] {
def +(other: Number[Double]) = DoubleNumber(value + other.value)
def /(other: Number[Double]) = DoubleNumber(value / other.value)
def /(other: Int) = DoubleNumber(value / other)
}
object Stat {
def mean[A](xs: Seq[Number[A]): Number[A] =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value
}
object Stat {
def mean[A](xs: Seq[A]): A =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A]): A =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A]): A =
xs.reduce(_ + _) / xs.size
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A]): A =
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
trait Number[A] {
def plus(n1: A, n2: A): A
def divide(n1: A, n2: A): A
def divide(n1: A, n2: Int): A
}
trait Number[A] {
def plus(n1: A, n2: A): A
def divide(n1: A, n2: A): A
def divide(n1: A, n2: Int): A
}
object Number {
implicit object BigDecimalNumber extends Number[BigDecimal] {
def plus(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 + n2
def divide(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 / n2
def divide(n1: BigDecimal, n2: Int): BigDecimal = n1 / n2
}
trait Number[A] {
def plus(n1: A, n2: A): A
def divide(n1: A, n2: A): A
def divide(n1: A, n2: Int): A
}
object Number {
implicit object BigDecimalNumber extends Number[BigDecimal] {
def plus(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 + n2
def divide(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 / n2
def divide(n1: BigDecimal, n2: Int): BigDecimal = n1 / n2
}
implicit object IntNumber extends Number[Int] {
def plus(n1: Int, n2: Int): Int = n1 + n2
def divide(n1: Int, n2: Int): Int = n1 / n2
}
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Order {
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))(BigDecimalNumber)
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Order {
import Number._
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))(BigDecimalNumber)
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Order {
import Number._
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Order {
import Number._
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Number {
implicit object BigDecimalNumber extends Number[BigDecimal] {..}
implicit object IntNumber extends Number[Int] {..}
}
object Stat {
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Number {
implicit object BigDecimalNumber extends Number[BigDecimal] {..}
implicit object IntNumber extends Number[Int] {..}
implicit class NumberOps[A](a: A)(implicit number: Number[A]) {
def +(other: A) = number.plus(a, other)
def /(other: A) = number.divide(a, other)
def /(other: Int) = number.divide(a, other)
}
}
object Stat {
import Number._
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Number {
implicit object BigDecimalNumber extends Number[BigDecimal] {..}
implicit object IntNumber extends Number[Int] {..}
implicit class NumberOps[A](a: A)(implicit number: Number[A]) {
def +(other: A) = number.plus(a, other)
def /(other: A) = number.divide(a, other)
def /(other: Int) = number.divide(a, other)
}
}
object Stat {
import Number._
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
number.divide(xs.reduce(number.plus),xs.size)
}
object Number {
implicit object BigDecimalNumber extends Number[BigDecimal] {..}
implicit object IntNumber extends Number[Int] {..}
implicit class NumberOps[A](a: A)(implicit number: Number[A]) {
def +(other: A) = number.plus(a, other)
def /(other: A) = number.divide(a, other)
def /(other: Int) = number.divide(a, other)
}
}
object Stat {
import Number._
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
xs.reduce(_ + _) / xs.size
}
object Number {
implicit object BigDecimalNumber extends Number[BigDecimal] {..}
implicit object IntNumber extends Number[Int] {..}
implicit class NumberOps[A](a: A)(implicit number: Number[A]) {
def +(other: A) = number.plus(a, other)
def /(other: A) = number.divide(a, other)
def /(other: Int) = number.divide(a, other)
}
}
object Stat {
import Number._
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
xs.reduce(_ + _) / xs.size
}
object Order {
import Number._
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
[info] OrderTest:
[info] - should evaluate order
[info] - should calculate average
[info] - should serialize to json
sealed trait JsonValue
case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue
case class JsonArray(elems: List[JsonValue]) extends JsonValue
case class JsonString(value: String) extends JsonValue
case class JsonNumber(value: BigDecimal) extends JsonValue
object JsonWriter {
def write(json: JsonValue): String = ...
}
trait JsonSerializable {
def toJson: JsonValue
}
object JsonSerializer {
def write(serializable: JsonSerializable) =
JsonWriter.write(serializable.toJson)
}
sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = ...
def toJson: JsonValue = JsonObject(Map(
"type" -> JsonString("general"),
"products" -> JsonArray(products.map(_.toJson))
))
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
trait JsonSerializable {
def toJson: JsonValue
}
object JsonSerializer {
def write(serializable: JsonSerializable) =
JsonWriter.write(serializable.toJson)
}
object JsonSerializer {
def write(serializable: JsonSerializable) =
JsonWriter.write(serializable.toJson)
}
object JsonSerializer {
def write[A](a: A) =
JsonWriter.write( toJson(a))
}
object JsonSerializer {
def write[A](a: A)(implicit json: Json[A]) =
JsonWriter.write(json.toJson(a))
}
object JsonSerializer {
def write[A](a: A)(implicit json: Json[A]) =
JsonWriter.write(json.toJson(a))
}
object JsonSerializer {
def write[A](a: A)(implicit json: Json[A]) =
JsonWriter.write(json.toJson(a))
}
trait Json[-A] {
def toJson(a: A): JsonValue
}
object JsonSerializer {
def write[A](a: A)(implicit json: Json[A]) =
JsonWriter.write(json.toJson(a))
}
object OrderJson {
implicit object ProductToJson extends Json[Product] {
def toJson(product: Product): JsonValue = ...
}
implicit object OrderToJson extends Json[Order] {
def toJson(order: Order): JsonValue = ...
}
}
object OrderJson {
implicit object ProductToJson extends Json[Product] {
def toJson(product: Product): JsonValue = ...
}
implicit object OrderToJson extends Json[Order] {
def toJson(order: Order): JsonValue = ...
}
}
object OrderJson {
implicit object ProductToJson extends Json[Product] {
def toJson(product: Product): JsonValue = ...
}
implicit object OrderToJson extends Json[Order] {
def toJson(order: Order): JsonValue = ...
}
}
implicit object ProductToJson extends Json[Product] {
def toJson(product: Product): JsonValue = product match {
case BasicProduct(id, price) =>
JsonObject(Map(
"type" -> JsonString("basic"),
"id" -> JsonNumber(BigDecimal(id)),
"price" -> JsonNumber(price)
))
case DiscountedProduct(product, discount) =>
JsonObject(Map(
"type" -> JsonString("discounted"),
"product" -> toJson(product),
"discount" -> JsonNumber(discount)
))
case OutOfStock() =>
JsonString("out of stock")
}
}
implicit object OrderToJson extends Json[Order] {
def toJson(order: Order): JsonValue = order match {
case GeneralOrder(products) =>
JsonObject(Map(
"type" -> JsonString("general"),
"products" -> JsonArray(products.map(ProductToJson.toJson))
))
case ComplexOrder(orders) =>
JsonObject(Map(
"type" -> JsonString("complex"),
"orders" -> JsonArray(orders.map(toJson))
))
case CancelledOrder() =>
JsonString("cancelled order")
}
}
object OrderJson {
implicit object ProductToJson extends Json[Product] {
def toJson(product: Product): JsonValue = ...
}
implicit object OrderToJson extends Json[Order] {
def toJson(order: Order): JsonValue = ...
}
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
import OrderJson._
JsonSerializer.write(order) should equal(expectedJson)
}
test("should serialize to json") {
val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)
val o2 = CancelledOrder
val order = ComplexOrder(o1 :: o2 :: Nil)
val expectedJson = """{
"type: "complex"",
"orders: [{
"type: "general"",
"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"
},
"cancelled order"]"
}"""
import OrderJson._
JsonSerializer.write(order) should equal(expectedJson)
}
[info] OrderTest:
[info] - should evaluate order
[info] - should calculate average
[info] - should serialize to json
trait Evaluatable[T] { def evaluate: T }
sealed trait Product extends Evaluatable[BigDecimal]
case class BasicProduct(id: Int, price: BigDecimal) extends Product {
def evaluate: BigDecimal = price
}
case class DiscountedProduct(product: Product, discount: Double) extends Product {
def evaluate: BigDecimal = product.evaluate * (1 - discount)
}
case object OutOfStock extends Product {
def evaluate: BigDecimal = BigDecimal("0.0")
}
trait Evaluatable[T] { def evaluate: T }
sealed trait Order extends Evaluatable[BigDecimal]
case object CancelledOrder extends Order {
def evaluate: BigDecimal = BigDecimal("0.0")
}
case class ComplexOrder(orders: List[Order]) extends Order {
def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + o.evaluate
}
}
case class GeneralOrder(products: List[Product]) extends Order {
def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + p.evaluate
}
}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Order {
implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] {
def evaluate(product: Product): BigDecimal = product match {
case BasicProduct(id, price) => price
case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount)
case OutOfStock() => BigDecimal("0.0")
}}
implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] {
def evaluate(order: Order): BigDecimal = order match {
case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + ProductEvaluate.evaluate(p)
}
case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + evaluate(o)
}
case CancelledOrder() => BigDecimal("0.0")
}}}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Order {
implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] {
def evaluate(product: Product): BigDecimal = product match {
case BasicProduct(id, price) => price
case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount)
case OutOfStock() => BigDecimal("0.0")
}}
implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] {
def evaluate(order: Order): BigDecimal = order match {
case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + ProductEvaluate.evaluate(p)
}
case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + evaluate(o)
}
case CancelledOrder() => BigDecimal("0.0")
}}}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Order {
implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] {
def evaluate(product: Product): BigDecimal = product match {
case BasicProduct(id, price) => price
case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount)
case OutOfStock() => BigDecimal("0.0")
}}
implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] {
def evaluate(order: Order): BigDecimal = order match {
case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + ProductEvaluate.evaluate(p)
}
case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + evaluate(o)
}
case CancelledOrder() => BigDecimal("0.0")
}}}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Order {
implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] {
def evaluate(product: Product): BigDecimal = product match {
case BasicProduct(id, price) => price
case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount)
case OutOfStock() => BigDecimal("0.0")
}}
implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] {
def evaluate(order: Order): BigDecimal = order match {
case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) {
case (acc, p) => acc + ProductEvaluate.evaluate(p)
}
case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) {
case (acc, o) => acc + evaluate(o)
}
case CancelledOrder() => BigDecimal("0.0")
}}}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Order {
import Number._
def average(orders: Seq[Order]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Evaluate {
implicit class EvaluateOps[-A, T](a: A)(implicit ev: Evaluate[A, T]) {
def evaluate = ev.evaluate(a)
}
}
object Order {
import Number._
def average(orders: Seq[Order])(implicit ev: Evaluate[Order, BigDecimal]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Evaluate {
implicit class EvaluateOps[-A, T](a: A)(implicit ev: Evaluate[A, T]) {
def evaluate = ev.evaluate(a)
}
}
object Order {
import Number._
def average(orders: Seq[Order])(implicit ev: Evaluate[Order, BigDecimal]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
trait Evaluate[-A, T] { def evaluate(a: A): T }
object Evaluate {
implicit class EvaluateOps[-A, T](a: A)(implicit ev: Evaluate[A, T]) {
def evaluate = ev.evaluate(a)
}
}
object Order {
import Number._
def average(orders: Seq[Order])(implicit ev: Evaluate[Order, BigDecimal]): BigDecimal =
Stat.mean(orders.map(_.evaluate))
}
sealed trait Order
case class GeneralOrder(products: List[Product]) extends Order
case object CancelledOrder extends Order
case class ComplexOrder(orders: List[Order]) extends Order
sealed trait Product
case class BasicProduct(id: Int, price: BigDecimal) extends Product
case class DiscountedProduct(product: Product,
discount: Double) extends Product
case object OutOfStock extends Product
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Domain & Feature Requests
Feature Requests:
● Present current state of orders (JSON)
● Calculate final checkout
● Calculate average Order price
● “Simplify” Orders
Act.4: “Enlightenment”
Research
Definitions
Definitions
● Type classes
Definitions
● Type classes
○ Ad-hoc polymorphism
● Abstract Data Type (ADT)
Our goal:
● DRY principle
● Separation of concerns
● Epic decoupling
● Clean API
● Minimal Boilerplate
Where to go next
1. Semigroup
2. Monoid
3. Functor
4. Applicative
5. Monad!
All are just type classes with some laws. That’s it!
Links & Resources
● https://github.com/rabbitonweb/scala_typeclasses
● https://inoio.de/blog/2014/07/19/type-class-101-semigroup/
● http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-
part-12-type-classes.html
● https://www.youtube.com/watch?v=sVMES4RZF-8
● http://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf
● https://www.destroyallsoftware.com/misc/reject.pdf
● http://southpark.cc.com/avatar
● http://www.tandemic.com/wp-content/uploads/Definition.png
And that’s all folks!
And that’s all folks!
Paweł Szulc
And that’s all folks!
Paweł Szulc
twitter: @rabbitonweb
And that’s all folks!
Paweł Szulc
twitter: @rabbitonweb
blog: http://rabbitonweb.com
And that’s all folks!
Paweł Szulc
twitter: @rabbitonweb
blog: http://rabbitonweb.com
github: https://github.com/rabbitonweb
And that’s all folks!
Paweł Szulc
twitter: @rabbitonweb
blog: http://rabbitonweb.com
github: https://github.com/rabbitonweb
Questions?
And that’s all folks!
Paweł Szulc
twitter: @rabbitonweb
blog: http://rabbitonweb.com
github: https://github.com/rabbitonweb
Questions?
Thank you!
Bonus!
object Stat {
import Number._
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
xs.reduce(_ + _) / xs.size
}
object Stat {
import Number._
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
xs.reduce(_ + _) / xs.size
}
object Stat {
import Number._
def mean[A : Number](xs: Seq[A]): A =
xs.reduce(_ + _) / xs.size
}
object Stat {
import Number._
def mean[A](xs: Seq[A])(implicit number: Number[A]): A =
xs.reduce(_ + _) / xs.size
}
object Stat {
import Number._
def mean[A : Number](xs: Seq[A]): A =
xs.reduce(_ + _) / xs.size
}
object JsonSerializer {
def write[A](a: A)(implicit json: Json[A]) =
JsonWriter.write(json.toJson(a))
}
object JsonSerializer {
def write[A](a: A)(implicit json: Json[A]) =
JsonWriter.write(json.toJson(a))
}
object JsonSerializer {
def write[A : Json](a: A) =
JsonWriter.write(implicitly[Json[A]].toJson(a))
}
object JsonSerializer {
def write[A](a: A)(implicit json: Json[A]) =
JsonWriter.write(json.toJson(a))
}
object JsonSerializer {
def write[A : Json](a: A) =
JsonWriter.write(implicitly[Json[A]].toJson(a))
}

More Related Content

What's hot

Postgres rules
Postgres rulesPostgres rules
Postgres rules
gisborne
 
Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2
Martin Zapletal
 
ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2
RORLAB
 
The Ring programming language version 1.5.3 book - Part 37 of 184
The Ring programming language version 1.5.3 book - Part 37 of 184The Ring programming language version 1.5.3 book - Part 37 of 184
The Ring programming language version 1.5.3 book - Part 37 of 184
Mahmoud Samir Fayed
 
qooxdoo Form Management
qooxdoo Form Managementqooxdoo Form Management
qooxdoo Form Management
Martin Wittemann
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
Darwin Durand
 
MaintainStaffTable
MaintainStaffTableMaintainStaffTable
MaintainStaffTable
William Rutherford
 
Php forum2015 tomas_final
Php forum2015 tomas_finalPhp forum2015 tomas_final
Php forum2015 tomas_final
Bertrand Matthelie
 
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
Ontico
 
The Ring programming language version 1.3 book - Part 28 of 88
The Ring programming language version 1.3 book - Part 28 of 88The Ring programming language version 1.3 book - Part 28 of 88
The Ring programming language version 1.3 book - Part 28 of 88
Mahmoud Samir Fayed
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
Yevhen Bobrov
 
Create a Customized GMF DnD Framework
Create a Customized GMF DnD FrameworkCreate a Customized GMF DnD Framework
Create a Customized GMF DnD Framework
Kaniska Mandal
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#
Vagif Abilov
 
supporting t-sql scripts for Heap vs clustered table
supporting t-sql scripts for Heap vs clustered tablesupporting t-sql scripts for Heap vs clustered table
supporting t-sql scripts for Heap vs clustered table
Mahabubur Rahaman
 
The Ring programming language version 1.2 book - Part 26 of 84
The Ring programming language version 1.2 book - Part 26 of 84The Ring programming language version 1.2 book - Part 26 of 84
The Ring programming language version 1.2 book - Part 26 of 84
Mahmoud Samir Fayed
 
Sql
SqlSql
BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7
Georgi Kodinov
 
Performante Java Enterprise Applikationen trotz O/R-Mapping
Performante Java Enterprise Applikationen trotz O/R-MappingPerformante Java Enterprise Applikationen trotz O/R-Mapping
Performante Java Enterprise Applikationen trotz O/R-Mapping
Simon Martinelli
 
Easy Button
Easy ButtonEasy Button
Easy Button
Adam Dale
 

What's hot (19)

Postgres rules
Postgres rulesPostgres rules
Postgres rules
 
Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2
 
ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2
 
The Ring programming language version 1.5.3 book - Part 37 of 184
The Ring programming language version 1.5.3 book - Part 37 of 184The Ring programming language version 1.5.3 book - Part 37 of 184
The Ring programming language version 1.5.3 book - Part 37 of 184
 
qooxdoo Form Management
qooxdoo Form Managementqooxdoo Form Management
qooxdoo Form Management
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
 
MaintainStaffTable
MaintainStaffTableMaintainStaffTable
MaintainStaffTable
 
Php forum2015 tomas_final
Php forum2015 tomas_finalPhp forum2015 tomas_final
Php forum2015 tomas_final
 
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
CREATE INDEX … USING VODKA. VODKA CONNECTING INDEXES, Олег Бартунов, Александ...
 
The Ring programming language version 1.3 book - Part 28 of 88
The Ring programming language version 1.3 book - Part 28 of 88The Ring programming language version 1.3 book - Part 28 of 88
The Ring programming language version 1.3 book - Part 28 of 88
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
 
Create a Customized GMF DnD Framework
Create a Customized GMF DnD FrameworkCreate a Customized GMF DnD Framework
Create a Customized GMF DnD Framework
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#
 
supporting t-sql scripts for Heap vs clustered table
supporting t-sql scripts for Heap vs clustered tablesupporting t-sql scripts for Heap vs clustered table
supporting t-sql scripts for Heap vs clustered table
 
The Ring programming language version 1.2 book - Part 26 of 84
The Ring programming language version 1.2 book - Part 26 of 84The Ring programming language version 1.2 book - Part 26 of 84
The Ring programming language version 1.2 book - Part 26 of 84
 
Sql
SqlSql
Sql
 
BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7BGOUG15: JSON support in MySQL 5.7
BGOUG15: JSON support in MySQL 5.7
 
Performante Java Enterprise Applikationen trotz O/R-Mapping
Performante Java Enterprise Applikationen trotz O/R-MappingPerformante Java Enterprise Applikationen trotz O/R-Mapping
Performante Java Enterprise Applikationen trotz O/R-Mapping
 
Easy Button
Easy ButtonEasy Button
Easy Button
 

Viewers also liked

Real world gobbledygook
Real world gobbledygookReal world gobbledygook
Real world gobbledygook
Pawel Szulc
 
The cats toolbox a quick tour of some basic typeclasses
The cats toolbox  a quick tour of some basic typeclassesThe cats toolbox  a quick tour of some basic typeclasses
The cats toolbox a quick tour of some basic typeclasses
Pawel Szulc
 
Introduction to type classes
Introduction to type classesIntroduction to type classes
Introduction to type classes
Pawel Szulc
 
Apache spark when things go wrong
Apache spark   when things go wrongApache spark   when things go wrong
Apache spark when things go wrong
Pawel Szulc
 
Writing your own RDD for fun and profit
Writing your own RDD for fun and profitWriting your own RDD for fun and profit
Writing your own RDD for fun and profit
Pawel Szulc
 
Functional Programming & Event Sourcing - a pair made in heaven
Functional Programming & Event Sourcing - a pair made in heavenFunctional Programming & Event Sourcing - a pair made in heaven
Functional Programming & Event Sourcing - a pair made in heaven
Pawel Szulc
 
“Going bananas with recursion schemes for fixed point data types”
“Going bananas with recursion schemes for fixed point data types”“Going bananas with recursion schemes for fixed point data types”
“Going bananas with recursion schemes for fixed point data types”
Pawel Szulc
 
Apache spark workshop
Apache spark workshopApache spark workshop
Apache spark workshop
Pawel Szulc
 
Going bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data typesGoing bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data types
Pawel Szulc
 
Make your programs Free
Make your programs FreeMake your programs Free
Make your programs Free
Pawel Szulc
 

Viewers also liked (10)

Real world gobbledygook
Real world gobbledygookReal world gobbledygook
Real world gobbledygook
 
The cats toolbox a quick tour of some basic typeclasses
The cats toolbox  a quick tour of some basic typeclassesThe cats toolbox  a quick tour of some basic typeclasses
The cats toolbox a quick tour of some basic typeclasses
 
Introduction to type classes
Introduction to type classesIntroduction to type classes
Introduction to type classes
 
Apache spark when things go wrong
Apache spark   when things go wrongApache spark   when things go wrong
Apache spark when things go wrong
 
Writing your own RDD for fun and profit
Writing your own RDD for fun and profitWriting your own RDD for fun and profit
Writing your own RDD for fun and profit
 
Functional Programming & Event Sourcing - a pair made in heaven
Functional Programming & Event Sourcing - a pair made in heavenFunctional Programming & Event Sourcing - a pair made in heaven
Functional Programming & Event Sourcing - a pair made in heaven
 
“Going bananas with recursion schemes for fixed point data types”
“Going bananas with recursion schemes for fixed point data types”“Going bananas with recursion schemes for fixed point data types”
“Going bananas with recursion schemes for fixed point data types”
 
Apache spark workshop
Apache spark workshopApache spark workshop
Apache spark workshop
 
Going bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data typesGoing bananas with recursion schemes for fixed point data types
Going bananas with recursion schemes for fixed point data types
 
Make your programs Free
Make your programs FreeMake your programs Free
Make your programs Free
 

Similar to Introduction to type classes in 30 min

Mongo db ecommerce
Mongo db ecommerceMongo db ecommerce
Mongo db ecommerce
christkv
 
The Time to Defer is Now
The Time to Defer is NowThe Time to Defer is Now
The Time to Defer is Now
Michael Diamant
 
Joy of scala
Joy of scalaJoy of scala
Joy of scala
Maxim Novak
 
Query for json databases
Query for json databasesQuery for json databases
Query for json databases
Binh Le
 
Functional DDD
Functional DDDFunctional DDD
Functional DDD
Alessandro Melchiori
 
Kotlin Redux
Kotlin ReduxKotlin Redux
Kotlin Redux
Manideep Polireddi
 
Kotlin dsl
Kotlin dslKotlin dsl
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design Principles
Jon Kruger
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
WorkingWithSlick2.1.0
WorkingWithSlick2.1.0WorkingWithSlick2.1.0
WorkingWithSlick2.1.0
Knoldus Inc.
 
MongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB World 2018: Keynote
MongoDB World 2018: Keynote
MongoDB
 
The Ring programming language version 1.7 book - Part 48 of 196
The Ring programming language version 1.7 book - Part 48 of 196The Ring programming language version 1.7 book - Part 48 of 196
The Ring programming language version 1.7 book - Part 48 of 196
Mahmoud Samir Fayed
 
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your DataMongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
MongoDB
 
Learning from GOOS - work in progress
Learning from GOOS - work in progressLearning from GOOS - work in progress
Learning from GOOS - work in progress
Olaf Lewitz
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
Tomas Jansson
 
The Ring programming language version 1.5 book - Part 8 of 31
The Ring programming language version 1.5 book - Part 8 of 31The Ring programming language version 1.5 book - Part 8 of 31
The Ring programming language version 1.5 book - Part 8 of 31
Mahmoud Samir Fayed
 
ADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developers
Bartosz Kosarzycki
 
Why Scala is the better Java
Why Scala is the better JavaWhy Scala is the better Java
Why Scala is the better Java
Thomas Kaiser
 
Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecord
scalaconfjp
 
Testing Without Writing Tests
Testing Without Writing TestsTesting Without Writing Tests
Testing Without Writing Tests
Víctor Muñoz
 

Similar to Introduction to type classes in 30 min (20)

Mongo db ecommerce
Mongo db ecommerceMongo db ecommerce
Mongo db ecommerce
 
The Time to Defer is Now
The Time to Defer is NowThe Time to Defer is Now
The Time to Defer is Now
 
Joy of scala
Joy of scalaJoy of scala
Joy of scala
 
Query for json databases
Query for json databasesQuery for json databases
Query for json databases
 
Functional DDD
Functional DDDFunctional DDD
Functional DDD
 
Kotlin Redux
Kotlin ReduxKotlin Redux
Kotlin Redux
 
Kotlin dsl
Kotlin dslKotlin dsl
Kotlin dsl
 
Solid Software Design Principles
Solid Software Design PrinciplesSolid Software Design Principles
Solid Software Design Principles
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
WorkingWithSlick2.1.0
WorkingWithSlick2.1.0WorkingWithSlick2.1.0
WorkingWithSlick2.1.0
 
MongoDB World 2018: Keynote
MongoDB World 2018: KeynoteMongoDB World 2018: Keynote
MongoDB World 2018: Keynote
 
The Ring programming language version 1.7 book - Part 48 of 196
The Ring programming language version 1.7 book - Part 48 of 196The Ring programming language version 1.7 book - Part 48 of 196
The Ring programming language version 1.7 book - Part 48 of 196
 
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your DataMongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
 
Learning from GOOS - work in progress
Learning from GOOS - work in progressLearning from GOOS - work in progress
Learning from GOOS - work in progress
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
 
The Ring programming language version 1.5 book - Part 8 of 31
The Ring programming language version 1.5 book - Part 8 of 31The Ring programming language version 1.5 book - Part 8 of 31
The Ring programming language version 1.5 book - Part 8 of 31
 
ADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developers
 
Why Scala is the better Java
Why Scala is the better JavaWhy Scala is the better Java
Why Scala is the better Java
 
Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecord
 
Testing Without Writing Tests
Testing Without Writing TestsTesting Without Writing Tests
Testing Without Writing Tests
 

More from Pawel Szulc

Getting acquainted with Lens
Getting acquainted with LensGetting acquainted with Lens
Getting acquainted with Lens
Pawel Szulc
 
Impossibility
ImpossibilityImpossibility
Impossibility
Pawel Szulc
 
Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)
Pawel Szulc
 
Painless Haskell
Painless HaskellPainless Haskell
Painless Haskell
Pawel Szulc
 
Trip with monads
Trip with monadsTrip with monads
Trip with monads
Pawel Szulc
 
Trip with monads
Trip with monadsTrip with monads
Trip with monads
Pawel Szulc
 
Illogical engineers
Illogical engineersIllogical engineers
Illogical engineers
Pawel Szulc
 
RChain - Understanding Distributed Calculi
RChain - Understanding Distributed CalculiRChain - Understanding Distributed Calculi
RChain - Understanding Distributed Calculi
Pawel Szulc
 
Illogical engineers
Illogical engineersIllogical engineers
Illogical engineers
Pawel Szulc
 
Understanding distributed calculi in Haskell
Understanding distributed calculi in HaskellUnderstanding distributed calculi in Haskell
Understanding distributed calculi in Haskell
Pawel Szulc
 
Software engineering the genesis
Software engineering  the genesisSoftware engineering  the genesis
Software engineering the genesis
Pawel Szulc
 
Category theory is general abolute nonsens
Category theory is general abolute nonsensCategory theory is general abolute nonsens
Category theory is general abolute nonsens
Pawel Szulc
 
Fun never stops. introduction to haskell programming language
Fun never stops. introduction to haskell programming languageFun never stops. introduction to haskell programming language
Fun never stops. introduction to haskell programming language
Pawel Szulc
 
Know your platform. 7 things every scala developer should know about jvm
Know your platform. 7 things every scala developer should know about jvmKnow your platform. 7 things every scala developer should know about jvm
Know your platform. 7 things every scala developer should know about jvm
Pawel Szulc
 
Monads asking the right question
Monads  asking the right questionMonads  asking the right question
Monads asking the right question
Pawel Szulc
 
Apache Spark 101 [in 50 min]
Apache Spark 101 [in 50 min]Apache Spark 101 [in 50 min]
Apache Spark 101 [in 50 min]
Pawel Szulc
 
Javascript development done right
Javascript development done rightJavascript development done right
Javascript development done right
Pawel Szulc
 
Architektura to nie bzdura
Architektura to nie bzduraArchitektura to nie bzdura
Architektura to nie bzdura
Pawel Szulc
 
Testing and Testable Code
Testing and Testable CodeTesting and Testable Code
Testing and Testable Code
Pawel Szulc
 

More from Pawel Szulc (19)

Getting acquainted with Lens
Getting acquainted with LensGetting acquainted with Lens
Getting acquainted with Lens
 
Impossibility
ImpossibilityImpossibility
Impossibility
 
Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)Maintainable Software Architecture in Haskell (with Polysemy)
Maintainable Software Architecture in Haskell (with Polysemy)
 
Painless Haskell
Painless HaskellPainless Haskell
Painless Haskell
 
Trip with monads
Trip with monadsTrip with monads
Trip with monads
 
Trip with monads
Trip with monadsTrip with monads
Trip with monads
 
Illogical engineers
Illogical engineersIllogical engineers
Illogical engineers
 
RChain - Understanding Distributed Calculi
RChain - Understanding Distributed CalculiRChain - Understanding Distributed Calculi
RChain - Understanding Distributed Calculi
 
Illogical engineers
Illogical engineersIllogical engineers
Illogical engineers
 
Understanding distributed calculi in Haskell
Understanding distributed calculi in HaskellUnderstanding distributed calculi in Haskell
Understanding distributed calculi in Haskell
 
Software engineering the genesis
Software engineering  the genesisSoftware engineering  the genesis
Software engineering the genesis
 
Category theory is general abolute nonsens
Category theory is general abolute nonsensCategory theory is general abolute nonsens
Category theory is general abolute nonsens
 
Fun never stops. introduction to haskell programming language
Fun never stops. introduction to haskell programming languageFun never stops. introduction to haskell programming language
Fun never stops. introduction to haskell programming language
 
Know your platform. 7 things every scala developer should know about jvm
Know your platform. 7 things every scala developer should know about jvmKnow your platform. 7 things every scala developer should know about jvm
Know your platform. 7 things every scala developer should know about jvm
 
Monads asking the right question
Monads  asking the right questionMonads  asking the right question
Monads asking the right question
 
Apache Spark 101 [in 50 min]
Apache Spark 101 [in 50 min]Apache Spark 101 [in 50 min]
Apache Spark 101 [in 50 min]
 
Javascript development done right
Javascript development done rightJavascript development done right
Javascript development done right
 
Architektura to nie bzdura
Architektura to nie bzduraArchitektura to nie bzdura
Architektura to nie bzdura
 
Testing and Testable Code
Testing and Testable CodeTesting and Testable Code
Testing and Testable Code
 

Recently uploaded

一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理
一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理
一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理
kgyxske
 
Orca: Nocode Graphical Editor for Container Orchestration
Orca: Nocode Graphical Editor for Container OrchestrationOrca: Nocode Graphical Editor for Container Orchestration
Orca: Nocode Graphical Editor for Container Orchestration
Pedro J. Molina
 
Upturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in NashikUpturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in Nashik
Upturn India Technologies
 
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdfBaha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid
 
The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...
The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...
The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...
kalichargn70th171
 
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual PerfectionBuilding the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Applitools
 
Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)
wonyong hwang
 
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptxOperational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
sandeepmenon62
 
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
campbellclarkson
 
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical OperationsEnsuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
OnePlan Solutions
 
Microsoft-Power-Platform-Adoption-Planning.pptx
Microsoft-Power-Platform-Adoption-Planning.pptxMicrosoft-Power-Platform-Adoption-Planning.pptx
Microsoft-Power-Platform-Adoption-Planning.pptx
jrodriguezq3110
 
The Comprehensive Guide to Validating Audio-Visual Performances.pdf
The Comprehensive Guide to Validating Audio-Visual Performances.pdfThe Comprehensive Guide to Validating Audio-Visual Performances.pdf
The Comprehensive Guide to Validating Audio-Visual Performances.pdf
kalichargn70th171
 
Streamlining End-to-End Testing Automation
Streamlining End-to-End Testing AutomationStreamlining End-to-End Testing Automation
Streamlining End-to-End Testing Automation
Anand Bagmar
 
Beginner's Guide to Observability@Devoxx PL 2024
Beginner's  Guide to Observability@Devoxx PL 2024Beginner's  Guide to Observability@Devoxx PL 2024
Beginner's Guide to Observability@Devoxx PL 2024
michniczscribd
 
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSISDECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
Tier1 app
 
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptxMigration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
ervikas4
 
ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.
Maitrey Patel
 
How GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdfHow GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdf
Zycus
 
The Role of DevOps in Digital Transformation.pdf
The Role of DevOps in Digital Transformation.pdfThe Role of DevOps in Digital Transformation.pdf
The Role of DevOps in Digital Transformation.pdf
mohitd6
 

Recently uploaded (20)

一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理
一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理
一比一原版(sdsu毕业证书)圣地亚哥州立大学毕业证如何办理
 
Orca: Nocode Graphical Editor for Container Orchestration
Orca: Nocode Graphical Editor for Container OrchestrationOrca: Nocode Graphical Editor for Container Orchestration
Orca: Nocode Graphical Editor for Container Orchestration
 
Upturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in NashikUpturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in Nashik
 
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdfBaha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
 
The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...
The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...
The Power of Visual Regression Testing_ Why It Is Critical for Enterprise App...
 
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual PerfectionBuilding the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
 
bgiolcb
bgiolcbbgiolcb
bgiolcb
 
Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)
 
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptxOperational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
 
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
 
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical OperationsEnsuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
 
Microsoft-Power-Platform-Adoption-Planning.pptx
Microsoft-Power-Platform-Adoption-Planning.pptxMicrosoft-Power-Platform-Adoption-Planning.pptx
Microsoft-Power-Platform-Adoption-Planning.pptx
 
The Comprehensive Guide to Validating Audio-Visual Performances.pdf
The Comprehensive Guide to Validating Audio-Visual Performances.pdfThe Comprehensive Guide to Validating Audio-Visual Performances.pdf
The Comprehensive Guide to Validating Audio-Visual Performances.pdf
 
Streamlining End-to-End Testing Automation
Streamlining End-to-End Testing AutomationStreamlining End-to-End Testing Automation
Streamlining End-to-End Testing Automation
 
Beginner's Guide to Observability@Devoxx PL 2024
Beginner's  Guide to Observability@Devoxx PL 2024Beginner's  Guide to Observability@Devoxx PL 2024
Beginner's Guide to Observability@Devoxx PL 2024
 
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSISDECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
DECODING JAVA THREAD DUMPS: MASTER THE ART OF ANALYSIS
 
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptxMigration From CH 1.0 to CH 2.0 and  Mule 4.6 & Java 17 Upgrade.pptx
Migration From CH 1.0 to CH 2.0 and Mule 4.6 & Java 17 Upgrade.pptx
 
ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.ACE - Team 24 Wrapup event at ahmedabad.
ACE - Team 24 Wrapup event at ahmedabad.
 
How GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdfHow GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdf
 
The Role of DevOps in Digital Transformation.pdf
The Role of DevOps in Digital Transformation.pdfThe Role of DevOps in Digital Transformation.pdf
The Role of DevOps in Digital Transformation.pdf
 

Introduction to type classes in 30 min

  • 1. Having a cake and eating it too. Introduction to Type classes (in Scala)
  • 2.
  • 3. “The Story of a Blackout” In 4 acts
  • 4. Act.1: “Loss & Grief”
  • 5.
  • 6.
  • 7.
  • 8.
  • 9. 503 Service Temporarily Unavailable nginx
  • 10. 503 Service Temporarily Unavailable nginx
  • 11.
  • 12.
  • 13. The 5 Stages of Loss and Grief
  • 14. The 5 Stages of Loss and Grief 1. Denial
  • 15. The 5 Stages of Loss and Grief 1. Denial 2. Anger
  • 16. The 5 Stages of Loss and Grief 1. Denial 2. Anger 3. Bargaining
  • 17. The 5 Stages of Loss and Grief 1. Denial 2. Anger 3. Bargaining 4. Depression
  • 18. The 5 Stages of Loss and Grief 1. Denial 2. Anger 3. Bargaining 4. Depression 5. Acceptance
  • 19.
  • 24. Domain & Feature Requests Domain: ● Users place Orders in the auction system Order
  • 25. Domain & Feature Requests Domain: ● Users place Orders in the auction system ● Orders can be: ○ General - contain list of Products ○ Complex - combined from two or more other Orders ○ Cancelled - used to be fully fledged Orders, but now are cancelled Order General Complex Cancelled
  • 26. Domain & Feature Requests Domain: ● Users place Orders in the auction system ● Orders can be: ○ General - contain list of Products ○ Complex - combined from two or more other Orders ○ Cancelled - used to be fully fledged Orders, but now are cancelled ● Products can be: ○ Basic - id & price ○ Discounted - wrapped Product & discount ○ OutOfStock - used to be in warehouse, but now gone (sorry) Order General Complex Cancelled Product Basic Discounter Out of Stock
  • 27. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 28. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 29. sealed trait Order case class GeneralOrder(products: List[Product]) extends Order case object CancelledOrder extends Order case class ComplexOrder(orders: List[Order]) extends Order sealed trait Product case class BasicProduct(id: Int, price: BigDecimal) extends Product case class DiscountedProduct(product: Product, discount: Double) extends Product case object OutOfStock extends Product
  • 30. sealed trait Order case class GeneralOrder(products: List[Product]) extends Order case object CancelledOrder extends Order case class ComplexOrder(orders: List[Order]) extends Order sealed trait Product case class BasicProduct(id: Int, price: BigDecimal) extends Product case class DiscountedProduct(product: Product, discount: Double) extends Product case object OutOfStock extends Product
  • 31. sealed trait Order case class GeneralOrder(products: List[Product]) extends Order case object CancelledOrder extends Order case class ComplexOrder(orders: List[Order]) extends Order sealed trait Product case class BasicProduct(id: Int, price: BigDecimal) extends Product case class DiscountedProduct(product: Product, discount: Double) extends Product case object OutOfStock extends Product
  • 32. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 33. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 34. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 35. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 36. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 37. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 38. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 39. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) } [error] OrderTest.scala evaluate is not a member of jw.ComplexOrder [error] order.evaluate should equal (BigDecimal("11.0")) [error] ^ [error] one error found
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 47. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) } [error] OrderTest.scala evaluate is not a member of jw.ComplexOrder [error] order.evaluate should equal (BigDecimal("11.0")) [error] ^ [error] one error found
  • 48. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 49. sealed trait Order case class GeneralOrder(products: List[Product]) extends Order case object CancelledOrder extends Order case class ComplexOrder(orders: List[Order]) extends Order sealed trait Product case class BasicProduct(id: Int, price: BigDecimal) extends Product case class DiscountedProduct(product: Product, discount: Double) extends Product case object OutOfStock extends Product
  • 50. trait Evaluatable[T] { def evaluate: T } sealed trait Order extends Evaluatable[BigDecimal] case object CancelledOrder extends Order { def evaluate: BigDecimal = BigDecimal("0.0") } case class ComplexOrder(orders: List[Order]) extends Order { def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + o.evaluate } } case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + p.evaluate } }
  • 51. trait Evaluatable[T] { def evaluate: T } sealed trait Order extends Evaluatable[BigDecimal] case object CancelledOrder extends Order { def evaluate: BigDecimal = BigDecimal("0.0") } case class ComplexOrder(orders: List[Order]) extends Order { def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + o.evaluate } } case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + p.evaluate } }
  • 52. trait Evaluatable[T] { def evaluate: T } sealed trait Order extends Evaluatable[BigDecimal] case object CancelledOrder extends Order { def evaluate: BigDecimal = BigDecimal("0.0") } case class ComplexOrder(orders: List[Order]) extends Order { def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + o.evaluate } } case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + p.evaluate } }
  • 53. trait Evaluatable[T] { def evaluate: T } sealed trait Order extends Evaluatable[BigDecimal] case object CancelledOrder extends Order { def evaluate: BigDecimal = BigDecimal("0.0") } case class ComplexOrder(orders: List[Order]) extends Order { def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + o.evaluate } } case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + p.evaluate } }
  • 54. trait Evaluatable[T] { def evaluate: T } sealed trait Order extends Evaluatable[BigDecimal] case object CancelledOrder extends Order { def evaluate: BigDecimal = BigDecimal("0.0") } case class ComplexOrder(orders: List[Order]) extends Order { def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + o.evaluate } } case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + p.evaluate } }
  • 55. trait Evaluatable[T] { def evaluate: T } sealed trait Product extends Evaluatable[BigDecimal] case class BasicProduct(id: Int, price: BigDecimal) extends Product { def evaluate: BigDecimal = price } case class DiscountedProduct(product: Product, discount: Double) extends Product { def evaluate: BigDecimal = product.evaluate * (1 - discount) } case object OutOfStock extends Product { def evaluate: BigDecimal = BigDecimal("0.0") }
  • 56. trait Evaluatable[T] { def evaluate: T } sealed trait Product extends Evaluatable[BigDecimal] case class BasicProduct(id: Int, price: BigDecimal) extends Product { def evaluate: BigDecimal = price } case class DiscountedProduct(product: Product, discount: Double) extends Product { def evaluate: BigDecimal = product.evaluate * (1 - discount) } case object OutOfStock extends Product { def evaluate: BigDecimal = BigDecimal("0.0") }
  • 57. trait Evaluatable[T] { def evaluate: T } sealed trait Product extends Evaluatable[BigDecimal] case class BasicProduct(id: Int, price: BigDecimal) extends Product { def evaluate: BigDecimal = price } case class DiscountedProduct(product: Product, discount: Double) extends Product { def evaluate: BigDecimal = product.evaluate * (1 - discount) } case object OutOfStock extends Product { def evaluate: BigDecimal = BigDecimal("0.0") }
  • 58. trait Evaluatable[T] { def evaluate: T } sealed trait Product extends Evaluatable[BigDecimal] case class BasicProduct(id: Int, price: BigDecimal) extends Product { def evaluate: BigDecimal = price } case class DiscountedProduct(product: Product, discount: Double) extends Product { def evaluate: BigDecimal = product.evaluate * (1 - discount) } case object OutOfStock extends Product { def evaluate: BigDecimal = BigDecimal("0.0") }
  • 59. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) }
  • 60. test("should evaluate order") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = GeneralOrder(DiscountedProduct( product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o3 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: o3 :: Nil) order.evaluate should equal (BigDecimal("11.0")) } [info] OrderTest: [info] - should evaluate order
  • 61.
  • 62. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 63. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 64. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 65. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) }
  • 66. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) }
  • 67. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) }
  • 68. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) }
  • 69. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) }
  • 70. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) }
  • 71. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) }
  • 72. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) } [error] OrderTest.scala average is not a member of jw.Order [error] Order.average should equal (BigDecimal("5.0")) [error] ^ [error] one error found
  • 73. object Stat { def mean(xs: Seq[BigDecimal]): BigDecimal = ??? }
  • 74. object Stat { def mean(xs: Seq[BigDecimal]): BigDecimal = xs.reduce(_ + _) / xs.size }
  • 75. object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) } object Stat { def mean(xs: Seq[BigDecimal]): BigDecimal = xs.reduce(_ + _) / xs.size }
  • 76.
  • 77. AWESOME! I just need it to work for Doubles and Ints as well! Can you make it more generic? Thx!
  • 78. object Stat { def mean(xs: Seq[BigDecimal]): BigDecimal = xs.reduce(_ + _) / xs.size }
  • 79. object Stat { def mean(xs: Seq[Number]): Number = xs.reduce(_ + _) / xs.size }
  • 80. object Stat { def mean(xs: Seq[Number]): Number = xs.reduce(_ + _) / xs.size }
  • 81.
  • 82.
  • 83. trait Number[A] { def value: A def +(other: Number[A]): Number[A] def /(other: Number[A]): Number[A] def /(other: Int): Number[A] }
  • 84. trait Number[A] { def value: A def +(other: Number[A]): Number[A] def /(other: Number[A]): Number[A] def /(other: Int): Number[A] } case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] { def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value) def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value) def /(other: Int) = BigDecimalNumber(value / other) }
  • 85. trait Number[A] { def value: A def +(other: Number[A]): Number[A] def /(other: Number[A]): Number[A] def /(other: Int): Number[A] } case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] { def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value) def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value) def /(other: Int) = BigDecimalNumber(value / other) }
  • 86. trait Number[A] { def value: A def +(other: Number[A]): Number[A] def /(other: Number[A]): Number[A] def /(other: Int): Number[A] } case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] { def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value) def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value) def /(other: Int) = BigDecimalNumber(value / other) } case class IntNumber(value: Int) extends Number[Int] { def +(other: Number[Int]) = IntNumber(value + other.value) def /(other: Number[Int]) = IntNumber(value / other.value) def /(other: Int) = IntNumber(value / other) }
  • 87. trait Number[A] { def value: A def +(other: Number[A]): Number[A] def /(other: Number[A]): Number[A] def /(other: Int): Number[A] } case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] { def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value) def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value) def /(other: Int) = BigDecimalNumber(value / other) } case class IntNumber(value: Int) extends Number[Int] { def +(other: Number[Int]) = IntNumber(value + other.value) def /(other: Number[Int]) = IntNumber(value / other.value) def /(other: Int) = IntNumber(value / other) } case class DoubleNumber(value: Double) extends Number[Double] { def +(other: Number[Double]) = DoubleNumber(value + other.value) def /(other: Number[Double]) = DoubleNumber(value / other.value) def /(other: Int) = DoubleNumber(value / other) }
  • 88. object Stat { def mean(xs: Seq[BigDecimal]): BigDecimal = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 89. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 90. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 91. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 92. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 93. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 94. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))) }
  • 95. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))) }
  • 96. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))) }
  • 97. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value }
  • 98. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value }
  • 99. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value }
  • 100. test("should calculate average") { val o1 = GeneralOrder(DiscountedProduct(product = BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil) val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil) val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0")) } [info] OrderTest: [info] - should evaluate order [info] - should calculate average
  • 101.
  • 102. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 103. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 104. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 105. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 106. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 107. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 108. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 109. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 110. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 111. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) } [error] OrderTest.scala not found: value JsonSerializer [error] JsonSerializer.write(order) should equal(expectedJson) [error] ^
  • 112. object JsonSerializer { def write(order: Order): String = ... }
  • 113.
  • 114.
  • 115. I have few objects I also need to serialize to JSON. Can you make your code a bit more generic? Thanks!!!
  • 116. object JsonSerializer { def write(order: Order): String = ... }
  • 117. object JsonSerializer { def write(sth: ???): String = ... }
  • 118. object JsonSerializer { def write(serializable: JsonSerializable) = ... }
  • 119. object JsonSerializer { def write(serializable: JsonSerializable) = ... } trait JsonSerializable { def toJson: JsonValue }
  • 120. object JsonSerializer { def write(serializable: JsonSerializable) = JsonWriter.write(serializable.toJson) } trait JsonSerializable { def toJson: JsonValue }
  • 121. object JsonSerializer { def write(serializable: JsonSerializable) = JsonWriter.write(serializable.toJson) } trait JsonSerializable { def toJson: JsonValue }
  • 123. sealed trait JsonValue case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue case class JsonArray(elems: List[JsonValue]) extends JsonValue case class JsonString(value: String) extends JsonValue case class JsonNumber(value: BigDecimal) extends JsonValue
  • 124. sealed trait JsonValue case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue case class JsonArray(elems: List[JsonValue]) extends JsonValue case class JsonString(value: String) extends JsonValue case class JsonNumber(value: BigDecimal) extends JsonValue object JsonWriter { def write(json: JsonValue): String =
  • 125. sealed trait JsonValue case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue case class JsonArray(elems: List[JsonValue]) extends JsonValue case class JsonString(value: String) extends JsonValue case class JsonNumber(value: BigDecimal) extends JsonValue object JsonWriter { def write(json: JsonValue): String = json match { case JsonObject(elems) => val entries = for { (key, value) <- elems } yield s""""$key: ${write(value)}"""" "{" + entries.mkString(", ") + "}" case JsonArray(elems) => "[" + elems.map(write).mkString(", ") + "]" case JsonString(value) => s""""$value"""" case JsonNumber(value) => value.toString } }
  • 126. sealed trait JsonValue case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue case class JsonArray(elems: List[JsonValue]) extends JsonValue case class JsonString(value: String) extends JsonValue case class JsonNumber(value: BigDecimal) extends JsonValue object JsonWriter { def write(json: JsonValue): String = ... }
  • 127. sealed trait JsonValue case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue case class JsonArray(elems: List[JsonValue]) extends JsonValue case class JsonString(value: String) extends JsonValue case class JsonNumber(value: BigDecimal) extends JsonValue object JsonWriter { def write(json: JsonValue): String = ... } trait JsonSerializable { def toJson: JsonValue } object JsonSerializer { def write(serializable: JsonSerializable) = JsonWriter.write(serializable.toJson) }
  • 128. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
  • 129. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
  • 130. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable
  • 131. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = ... def toJson: JsonValue = JsonObject(Map( "type" -> JsonString("general"), "products" -> JsonArray(products.map(_.toJson)) )) }
  • 132. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable case object CancelledOrder extends Order { def evaluate: BigDecimal = ... def toJson: JsonValue = JsonString("cancelled order") }
  • 133. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable case class ComplexOrder(orders: List[Order]) extends Order { def evaluate: BigDecimal = ... def toJson: JsonValue = JsonObject(Map( "type" -> JsonString("complex"), "orders" -> JsonArray(orders.map(_.toJson))) ) }
  • 134. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable case class BasicProduct(id: Int, price: BigDecimal) extends Product { def evaluate: BigDecimal = ... def toJson: JsonValue = JsonObject(Map( "type" -> JsonString("basic"), "id" -> JsonNumber(BigDecimal(id)), "price" -> JsonNumber(price) )) }
  • 135. sealed trait Product extends Evaluatable[BigDecimal] with JsonSerializable case class DiscountedProduct(product: Product, discount: Double) extends Product { def evaluate: BigDecimal = ... def toJson: JsonValue = JsonObject(Map( "type" -> JsonString("discounted"), "product" -> product.toJson, "discount" -> JsonNumber(discount) )) }
  • 136. sealed trait Product extends Evaluatable[BigDecimal] with JsonSerializable case object OutOfStock extends Product { def evaluate: BigDecimal = ... def toJson: JsonValue = JsonString("out of stock") }
  • 137. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) } [info] OrderTest: [info] - should evaluate order [info] - should calculate average [info] - should serialize to json
  • 138. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 139. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 140.
  • 141.
  • 142.
  • 143.
  • 144. Our goal: ● DRY principle ● Separation of concerns ● Epic decoupling ● Clean API ● Minimal Boilerplate
  • 146. trait Number[A] { def value: A def +(other: Number[A]): Number[A] def /(other: Number[A]): Number[A] def /(other: Int): Number[A] } case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] { def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value) def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value) def /(other: Int) = BigDecimalNumber(value / other) } case class IntNumber(value: Int) extends Number[Int] { def +(other: Number[Int]) = IntNumber(value + other.value) def /(other: Number[Int]) = IntNumber(value / other.value) def /(other: Int) = IntNumber(value / other) } case class DoubleNumber(value: Double) extends Number[Double] { def +(other: Number[Double]) = DoubleNumber(value + other.value) def /(other: Number[Double]) = DoubleNumber(value / other.value) def /(other: Int) = DoubleNumber(value / other) }
  • 147. object Stat { def mean[A](xs: Seq[Number[A]): Number[A] = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value }
  • 148. object Stat { def mean[A](xs: Seq[A]): A = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 149. object Stat { def mean[A](xs: Seq[A]): A = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 150. object Stat { def mean[A](xs: Seq[A]): A = xs.reduce(_ + _) / xs.size } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 151. object Stat { def mean[A](xs: Seq[A]): A = } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 152. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 153. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 154. trait Number[A] { def plus(n1: A, n2: A): A def divide(n1: A, n2: A): A def divide(n1: A, n2: Int): A }
  • 155. trait Number[A] { def plus(n1: A, n2: A): A def divide(n1: A, n2: A): A def divide(n1: A, n2: Int): A } object Number { implicit object BigDecimalNumber extends Number[BigDecimal] { def plus(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 + n2 def divide(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 / n2 def divide(n1: BigDecimal, n2: Int): BigDecimal = n1 / n2 }
  • 156. trait Number[A] { def plus(n1: A, n2: A): A def divide(n1: A, n2: A): A def divide(n1: A, n2: Int): A } object Number { implicit object BigDecimalNumber extends Number[BigDecimal] { def plus(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 + n2 def divide(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 / n2 def divide(n1: BigDecimal, n2: Int): BigDecimal = n1 / n2 } implicit object IntNumber extends Number[Int] { def plus(n1: Int, n2: Int): Int = n1 + n2 def divide(n1: Int, n2: Int): Int = n1 / n2 } }
  • 157. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 158. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Order { def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate))(BigDecimalNumber) }
  • 159. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Order { import Number._ def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate))(BigDecimalNumber) }
  • 160. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Order { import Number._ def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 161. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Order { import Number._ def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 162. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Number { implicit object BigDecimalNumber extends Number[BigDecimal] {..} implicit object IntNumber extends Number[Int] {..} }
  • 163. object Stat { def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Number { implicit object BigDecimalNumber extends Number[BigDecimal] {..} implicit object IntNumber extends Number[Int] {..} implicit class NumberOps[A](a: A)(implicit number: Number[A]) { def +(other: A) = number.plus(a, other) def /(other: A) = number.divide(a, other) def /(other: Int) = number.divide(a, other) } }
  • 164. object Stat { import Number._ def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Number { implicit object BigDecimalNumber extends Number[BigDecimal] {..} implicit object IntNumber extends Number[Int] {..} implicit class NumberOps[A](a: A)(implicit number: Number[A]) { def +(other: A) = number.plus(a, other) def /(other: A) = number.divide(a, other) def /(other: Int) = number.divide(a, other) } }
  • 165. object Stat { import Number._ def mean[A](xs: Seq[A])(implicit number: Number[A]): A = number.divide(xs.reduce(number.plus),xs.size) } object Number { implicit object BigDecimalNumber extends Number[BigDecimal] {..} implicit object IntNumber extends Number[Int] {..} implicit class NumberOps[A](a: A)(implicit number: Number[A]) { def +(other: A) = number.plus(a, other) def /(other: A) = number.divide(a, other) def /(other: Int) = number.divide(a, other) } }
  • 166. object Stat { import Number._ def mean[A](xs: Seq[A])(implicit number: Number[A]): A = xs.reduce(_ + _) / xs.size } object Number { implicit object BigDecimalNumber extends Number[BigDecimal] {..} implicit object IntNumber extends Number[Int] {..} implicit class NumberOps[A](a: A)(implicit number: Number[A]) { def +(other: A) = number.plus(a, other) def /(other: A) = number.divide(a, other) def /(other: Int) = number.divide(a, other) } }
  • 167. object Stat { import Number._ def mean[A](xs: Seq[A])(implicit number: Number[A]): A = xs.reduce(_ + _) / xs.size } object Order { import Number._ def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 168. [info] OrderTest: [info] - should evaluate order [info] - should calculate average [info] - should serialize to json
  • 169.
  • 170.
  • 171. sealed trait JsonValue case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue case class JsonArray(elems: List[JsonValue]) extends JsonValue case class JsonString(value: String) extends JsonValue case class JsonNumber(value: BigDecimal) extends JsonValue object JsonWriter { def write(json: JsonValue): String = ... } trait JsonSerializable { def toJson: JsonValue } object JsonSerializer { def write(serializable: JsonSerializable) = JsonWriter.write(serializable.toJson) }
  • 172. sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = ... def toJson: JsonValue = JsonObject(Map( "type" -> JsonString("general"), "products" -> JsonArray(products.map(_.toJson)) )) }
  • 173. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 174. trait JsonSerializable { def toJson: JsonValue } object JsonSerializer { def write(serializable: JsonSerializable) = JsonWriter.write(serializable.toJson) }
  • 175. object JsonSerializer { def write(serializable: JsonSerializable) = JsonWriter.write(serializable.toJson) }
  • 176. object JsonSerializer { def write[A](a: A) = JsonWriter.write( toJson(a)) }
  • 177. object JsonSerializer { def write[A](a: A)(implicit json: Json[A]) = JsonWriter.write(json.toJson(a)) }
  • 178. object JsonSerializer { def write[A](a: A)(implicit json: Json[A]) = JsonWriter.write(json.toJson(a)) }
  • 179. object JsonSerializer { def write[A](a: A)(implicit json: Json[A]) = JsonWriter.write(json.toJson(a)) }
  • 180. trait Json[-A] { def toJson(a: A): JsonValue } object JsonSerializer { def write[A](a: A)(implicit json: Json[A]) = JsonWriter.write(json.toJson(a)) }
  • 181. object OrderJson { implicit object ProductToJson extends Json[Product] { def toJson(product: Product): JsonValue = ... } implicit object OrderToJson extends Json[Order] { def toJson(order: Order): JsonValue = ... } }
  • 182. object OrderJson { implicit object ProductToJson extends Json[Product] { def toJson(product: Product): JsonValue = ... } implicit object OrderToJson extends Json[Order] { def toJson(order: Order): JsonValue = ... } }
  • 183. object OrderJson { implicit object ProductToJson extends Json[Product] { def toJson(product: Product): JsonValue = ... } implicit object OrderToJson extends Json[Order] { def toJson(order: Order): JsonValue = ... } }
  • 184. implicit object ProductToJson extends Json[Product] { def toJson(product: Product): JsonValue = product match { case BasicProduct(id, price) => JsonObject(Map( "type" -> JsonString("basic"), "id" -> JsonNumber(BigDecimal(id)), "price" -> JsonNumber(price) )) case DiscountedProduct(product, discount) => JsonObject(Map( "type" -> JsonString("discounted"), "product" -> toJson(product), "discount" -> JsonNumber(discount) )) case OutOfStock() => JsonString("out of stock") } }
  • 185. implicit object OrderToJson extends Json[Order] { def toJson(order: Order): JsonValue = order match { case GeneralOrder(products) => JsonObject(Map( "type" -> JsonString("general"), "products" -> JsonArray(products.map(ProductToJson.toJson)) )) case ComplexOrder(orders) => JsonObject(Map( "type" -> JsonString("complex"), "orders" -> JsonArray(orders.map(toJson)) )) case CancelledOrder() => JsonString("cancelled order") } }
  • 186. object OrderJson { implicit object ProductToJson extends Json[Product] { def toJson(product: Product): JsonValue = ... } implicit object OrderToJson extends Json[Order] { def toJson(order: Order): JsonValue = ... } }
  • 187. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" JsonSerializer.write(order) should equal(expectedJson) }
  • 188. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" import OrderJson._ JsonSerializer.write(order) should equal(expectedJson) }
  • 189. test("should serialize to json") { val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil) val o2 = CancelledOrder val order = ComplexOrder(o1 :: o2 :: Nil) val expectedJson = """{ "type: "complex"", "orders: [{ "type: "general"", "products: [{"type: "basic"", "id: 10", "price: 10.2"}]" }, "cancelled order"]" }""" import OrderJson._ JsonSerializer.write(order) should equal(expectedJson) } [info] OrderTest: [info] - should evaluate order [info] - should calculate average [info] - should serialize to json
  • 190.
  • 191. trait Evaluatable[T] { def evaluate: T } sealed trait Product extends Evaluatable[BigDecimal] case class BasicProduct(id: Int, price: BigDecimal) extends Product { def evaluate: BigDecimal = price } case class DiscountedProduct(product: Product, discount: Double) extends Product { def evaluate: BigDecimal = product.evaluate * (1 - discount) } case object OutOfStock extends Product { def evaluate: BigDecimal = BigDecimal("0.0") }
  • 192. trait Evaluatable[T] { def evaluate: T } sealed trait Order extends Evaluatable[BigDecimal] case object CancelledOrder extends Order { def evaluate: BigDecimal = BigDecimal("0.0") } case class ComplexOrder(orders: List[Order]) extends Order { def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + o.evaluate } } case class GeneralOrder(products: List[Product]) extends Order { def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + p.evaluate } }
  • 193. trait Evaluate[-A, T] { def evaluate(a: A): T } object Order { implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] { def evaluate(product: Product): BigDecimal = product match { case BasicProduct(id, price) => price case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount) case OutOfStock() => BigDecimal("0.0") }} implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] { def evaluate(order: Order): BigDecimal = order match { case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + ProductEvaluate.evaluate(p) } case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + evaluate(o) } case CancelledOrder() => BigDecimal("0.0") }}}
  • 194. trait Evaluate[-A, T] { def evaluate(a: A): T } object Order { implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] { def evaluate(product: Product): BigDecimal = product match { case BasicProduct(id, price) => price case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount) case OutOfStock() => BigDecimal("0.0") }} implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] { def evaluate(order: Order): BigDecimal = order match { case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + ProductEvaluate.evaluate(p) } case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + evaluate(o) } case CancelledOrder() => BigDecimal("0.0") }}}
  • 195. trait Evaluate[-A, T] { def evaluate(a: A): T } object Order { implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] { def evaluate(product: Product): BigDecimal = product match { case BasicProduct(id, price) => price case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount) case OutOfStock() => BigDecimal("0.0") }} implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] { def evaluate(order: Order): BigDecimal = order match { case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + ProductEvaluate.evaluate(p) } case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + evaluate(o) } case CancelledOrder() => BigDecimal("0.0") }}}
  • 196. trait Evaluate[-A, T] { def evaluate(a: A): T } object Order { implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] { def evaluate(product: Product): BigDecimal = product match { case BasicProduct(id, price) => price case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount) case OutOfStock() => BigDecimal("0.0") }} implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] { def evaluate(order: Order): BigDecimal = order match { case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) { case (acc, p) => acc + ProductEvaluate.evaluate(p) } case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) { case (acc, o) => acc + evaluate(o) } case CancelledOrder() => BigDecimal("0.0") }}}
  • 197. trait Evaluate[-A, T] { def evaluate(a: A): T } object Order { import Number._ def average(orders: Seq[Order]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 198. trait Evaluate[-A, T] { def evaluate(a: A): T } object Evaluate { implicit class EvaluateOps[-A, T](a: A)(implicit ev: Evaluate[A, T]) { def evaluate = ev.evaluate(a) } } object Order { import Number._ def average(orders: Seq[Order])(implicit ev: Evaluate[Order, BigDecimal]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 199. trait Evaluate[-A, T] { def evaluate(a: A): T } object Evaluate { implicit class EvaluateOps[-A, T](a: A)(implicit ev: Evaluate[A, T]) { def evaluate = ev.evaluate(a) } } object Order { import Number._ def average(orders: Seq[Order])(implicit ev: Evaluate[Order, BigDecimal]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 200. trait Evaluate[-A, T] { def evaluate(a: A): T } object Evaluate { implicit class EvaluateOps[-A, T](a: A)(implicit ev: Evaluate[A, T]) { def evaluate = ev.evaluate(a) } } object Order { import Number._ def average(orders: Seq[Order])(implicit ev: Evaluate[Order, BigDecimal]): BigDecimal = Stat.mean(orders.map(_.evaluate)) }
  • 201.
  • 202. sealed trait Order case class GeneralOrder(products: List[Product]) extends Order case object CancelledOrder extends Order case class ComplexOrder(orders: List[Order]) extends Order sealed trait Product case class BasicProduct(id: Int, price: BigDecimal) extends Product case class DiscountedProduct(product: Product, discount: Double) extends Product case object OutOfStock extends Product
  • 203. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 204. Domain & Feature Requests Feature Requests: ● Present current state of orders (JSON) ● Calculate final checkout ● Calculate average Order price ● “Simplify” Orders
  • 205.
  • 210. Definitions ● Type classes ○ Ad-hoc polymorphism ● Abstract Data Type (ADT)
  • 211. Our goal: ● DRY principle ● Separation of concerns ● Epic decoupling ● Clean API ● Minimal Boilerplate
  • 212. Where to go next 1. Semigroup 2. Monoid 3. Functor 4. Applicative 5. Monad! All are just type classes with some laws. That’s it!
  • 213. Links & Resources ● https://github.com/rabbitonweb/scala_typeclasses ● https://inoio.de/blog/2014/07/19/type-class-101-semigroup/ ● http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala- part-12-type-classes.html ● https://www.youtube.com/watch?v=sVMES4RZF-8 ● http://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf ● https://www.destroyallsoftware.com/misc/reject.pdf ● http://southpark.cc.com/avatar ● http://www.tandemic.com/wp-content/uploads/Definition.png
  • 214. And that’s all folks!
  • 215. And that’s all folks! Paweł Szulc
  • 216. And that’s all folks! Paweł Szulc twitter: @rabbitonweb
  • 217. And that’s all folks! Paweł Szulc twitter: @rabbitonweb blog: http://rabbitonweb.com
  • 218. And that’s all folks! Paweł Szulc twitter: @rabbitonweb blog: http://rabbitonweb.com github: https://github.com/rabbitonweb
  • 219. And that’s all folks! Paweł Szulc twitter: @rabbitonweb blog: http://rabbitonweb.com github: https://github.com/rabbitonweb Questions?
  • 220. And that’s all folks! Paweł Szulc twitter: @rabbitonweb blog: http://rabbitonweb.com github: https://github.com/rabbitonweb Questions? Thank you!
  • 221. Bonus!
  • 222. object Stat { import Number._ def mean[A](xs: Seq[A])(implicit number: Number[A]): A = xs.reduce(_ + _) / xs.size }
  • 223. object Stat { import Number._ def mean[A](xs: Seq[A])(implicit number: Number[A]): A = xs.reduce(_ + _) / xs.size } object Stat { import Number._ def mean[A : Number](xs: Seq[A]): A = xs.reduce(_ + _) / xs.size }
  • 224. object Stat { import Number._ def mean[A](xs: Seq[A])(implicit number: Number[A]): A = xs.reduce(_ + _) / xs.size } object Stat { import Number._ def mean[A : Number](xs: Seq[A]): A = xs.reduce(_ + _) / xs.size }
  • 225. object JsonSerializer { def write[A](a: A)(implicit json: Json[A]) = JsonWriter.write(json.toJson(a)) }
  • 226. object JsonSerializer { def write[A](a: A)(implicit json: Json[A]) = JsonWriter.write(json.toJson(a)) } object JsonSerializer { def write[A : Json](a: A) = JsonWriter.write(implicitly[Json[A]].toJson(a)) }
  • 227. object JsonSerializer { def write[A](a: A)(implicit json: Json[A]) = JsonWriter.write(json.toJson(a)) } object JsonSerializer { def write[A : Json](a: A) = JsonWriter.write(implicitly[Json[A]].toJson(a)) }