Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Section 5 needs update regarding Lazy? #50

Open
mikolak-net opened this issue Sep 8, 2017 · 0 comments
Open

Section 5 needs update regarding Lazy? #50

mikolak-net opened this issue Sep 8, 2017 · 0 comments

Comments

@mikolak-net
Copy link

mikolak-net commented Sep 8, 2017

As far as I recall, there was a relatively recent SIP that improved the implicit resolution process, making the usage of Lazy redundant in at least some cases (quick research suggests this was before 2.12.0).

It would be perhaps advantageous to take it into account as its one less concept to hold in ones head when reading the book, for a number of code snippets. For example, here's a (somewhat modified, mostly replaced explicit trait instance creation with SAM resolution) an example for the code necessary for 5.3 that compiles without using Lazy:

import shapeless.labelled.FieldType
import shapeless.{::, HList, HNil, LabelledGeneric, Witness}

sealed trait JsonValue

case class JsonObject(fields: List[(String, JsonValue)]) extends JsonValue
case class JsonArray(items: List[JsonValue]) extends JsonValue
case class JsonString(value: String) extends JsonValue
case class JsonNumber(value: Double) extends JsonValue
case class JsonBoolean(value: Boolean) extends JsonValue
case object JsonNull extends JsonValue

trait JsonEncoder[A] {
  def encode(value: A): JsonValue
}

object JsonEncoder {
  def apply[A](implicit enc: JsonEncoder[A]): JsonEncoder[A] = enc

  implicit val stringEncoder: JsonEncoder[String] = JsonString.apply
  implicit val doubleEncoder: JsonEncoder[Double] = JsonNumber.apply
  implicit val intEncoder: JsonEncoder[Int] = i => JsonNumber(i)
  implicit val booleanEncoder: JsonEncoder[Boolean] = JsonBoolean.apply

  implicit def listEncoder[A](
      implicit enc: JsonEncoder[A]): JsonEncoder[List[A]] =
    l => JsonArray(l.map(enc.encode))

  implicit def optionEncoder[A](
      implicit enc: JsonEncoder[A]): JsonEncoder[Option[A]] =
    _.map(enc.encode).getOrElse(JsonNull)
}

trait JsonObjectEncoder[A] extends JsonEncoder[A] {
  def encode(value: A): JsonObject
}

object JsonObjectEncoder {

  implicit val hnilEncoder: JsonObjectEncoder[HNil] = _ => JsonObject(Nil)

  implicit def hlistObjectEncoder[K <: Symbol, H, T <: HList](
      implicit fieldKey: Witness.Aux[K],
      hEncoder: JsonEncoder[H], //Lazy was here
      tEncoder: JsonObjectEncoder[T])
    : JsonObjectEncoder[FieldType[K, H] :: T] = {
    val fieldName = fieldKey.value.name

    {
      case (head :: tail) =>
        JsonObject(
          (fieldName -> hEncoder.encode(head)) :: tEncoder.encode(tail).fields)
    }
  }

  implicit def genericObjectEncoder[A, H](
      implicit generic: LabelledGeneric.Aux[A, H],
      hListEncoder: JsonObjectEncoder[H]): JsonEncoder[A] = //and here
    (o: A) => hListEncoder.encode(generic.to(o))

}

case class IceCream(name: String, numCherries: Int, inCone: Boolean)

object test extends App {

  import JsonObjectEncoder._

  val iceCream = IceCream("Sundae", 1, inCone = false)

  println(JsonEncoder[IceCream].encode(iceCream))

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant