Skip to content

Section 5 needs update regarding Lazy? #50

Description

@mikolak-net

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))

}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions