Skip to content

Instantly share code, notes, and snippets.

@SystemFw
Last active August 14, 2017 23:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SystemFw/4f2f506e0eb95cd330b7a2ca27794a46 to your computer and use it in GitHub Desktop.
Save SystemFw/4f2f506e0eb95cd330b7a2ca27794a46 to your computer and use it in GitHub Desktop.
Shapeless: update some fields of a class with a Diff, generically
import shapeless._, labelled._, ops.hlist._
object Update extends Poly2 {
implicit def all[A, B, R1 <: HList, R2 <: HList](
implicit oldGen: LabelledGeneric.Aux[A, R1],
newGen: LabelledGeneric.Aux[B, R2],
z: ZipWith.Aux[R1, R2, Update.type, R1]) =
at[A, B] { (old, maybeNew) =>
val oldRepr = oldGen.to(old)
val newRepr = newGen.to(maybeNew)
oldGen.from(oldRepr.zipWith(newRepr)(Update))
}
implicit def repr[K <: Symbol, V] =
at[FieldType[K, V], FieldType[K, Option[V]]] { (old, maybeNew) =>
field[K](maybeNew getOrElse old)
}
}
object Example {
case class B(a: Int, b: Int)
case class Diff(a: Option[Int] = None, b: Option[Int] = None)
val a = Update(B(1, 3), Diff(Some(2)))
// res0: Example.B = B(2,3)
// compile time error if the formats are not compatible for field names or types
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment