Skip to content

Instantly share code, notes, and snippets.

@steinybot
Last active February 17, 2021 22:53
Show Gist options
  • Save steinybot/e8710f6ff40379bf2d0f2767b5784fd4 to your computer and use it in GitHub Desktop.
Save steinybot/e8710f6ff40379bf2d0f2767b5784fd4 to your computer and use it in GitHub Desktop.
Boo for Boopickle
package object pickle {
trait MyTypeA
// This has to have a type parameter.
trait MyTypeB[A]
import boopickle.Pickler
trait Implicits {
implicit lazy val myTypeAPickler: Pickler[MyTypeA] = ???
}
case class MyFixedTuple(a: List[MyTypeA], b: List[MyTypeB[Any]])
case class MyGenericTuple[A, B](a: A, b: B)
}
package pickle
import boopickle.DefaultBasic._
// This works.
object Good1 extends Implicits {
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle.DefaultBasic._
// Same as Good1 but the implicit is on the object instead of the val.
// Fails with:
// [error] /src/main/scala/pickle/Bad1.scala:19:25: diverging implicit expansion for type boopickle.DefaultBasic.P[T1]
// [error] starting with lazy value myTypeAPickler in trait Implicits
// [error] state.unpickle[List[MyTypeB[Any]]]
// [error] ^
object Bad1 extends Implicits {
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle.DefaultBasic._
// Same as Good1 but we don't call the MyFixedTuple.apply method (WTF!?).
// Fails with:
//error] /src/main/scala/pickle/Bad2.scala:18:23: diverging implicit expansion for type boopickle.Pickler[List[pickle.MyTypeB[Any]]]
// [error] starting with lazy value myTypeBPickler in object Bad2
// [error] state.unpickle[List[MyTypeB[Any]]]
// [error] ^
object Bad2 extends Implicits {
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
state.unpickle[List[MyTypeA]]
state.unpickle[List[MyTypeB[Any]]]
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle.DefaultBasic._
// Same as Good1 but we call the apply method of a tuple with type parameters (WTF!?).
// Fails with:
// [error] /src/main/scala/pickle/Bad3.scala:19:25: diverging implicit expansion for type boopickle.Pickler[List[pickle.MyTypeB[Any]]]
// [error] starting with lazy value myTypeBPickler in object Bad3
// [error] state.unpickle[List[MyTypeB[Any]]]
// [error] ^
object Bad3 extends Implicits {
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyGenericTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle._
// Same as Bad1 but we extend BasicImplicitPicklers instead of importing DefaultBasic._
// Fails with:
// [error] /src/main/scala/pickle/Bad4.scala:19:25: diverging implicit expansion for type pickle.Bad4.P[T]
// [error] starting with method iterablePickler in trait XCompatImplicitPicklers
// [error] state.unpickle[List[MyTypeB[Any]]]
// [error] ^
object Bad4 extends Implicits with PicklerHelper with XCompatImplicitPicklers {
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle._
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds
// Same as Bad1 but we define everything ourselves.
object Good2 extends Implicits {
implicit def iterablePickler[T: Pickler, V[_] <: Iterable[_]](implicit cbf: CanBuildFrom[Nothing, T, V[T]]): Pickler[V[T]] =
BasicPicklers.IterablePickler[T, V]
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle._
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds
// Same as Good2 but with the additional mapPickler.
// Fails with:
// [error] /src/main/scala/pickle/Bad5.scala:29:25: diverging implicit expansion for type boopickle.Pickler[T]
// [error] starting with method iterablePickler in object Bad5
// [error] state.unpickle[List[MyTypeB[Any]]]
// [error] ^
object Bad5 extends Implicits {
implicit def mapPickler[T: Pickler, S: Pickler, V[_, _] <: scala.collection.Map[_, _]](
implicit cbf: CanBuildFrom[Nothing, (T, S), V[T, S]]): Pickler[V[T, S]] =
BasicPicklers.MapPickler[T, S, V]
implicit def iterablePickler[T: Pickler, V[_] <: Iterable[_]](implicit cbf: CanBuildFrom[Nothing, T, V[T]]): Pickler[V[T]] =
BasicPicklers.IterablePickler[T, V]
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
// Same as Good1 but with the import moved into the object.
// Fails with:
// [error] /src/main/scala/pickle/Bad6.scala:19:25: diverging implicit expansion for type boopickle.DefaultBasic.P[T1]
// [error] starting with lazy value myTypeAPickler in trait Implicits
// [error] state.unpickle[List[MyTypeB[Any]]]
// [error] ^
object Bad6 extends Implicits {
import boopickle.DefaultBasic._
implicit lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle.DefaultBasic.{mapPickler => _, _}
// Same as Bad1 but we hide the mapPickler.
object Good3 extends Implicits {
// implicit def listPickler[A: Pickler]: Pickler[List[A]] = boopickle.DefaultBasic.iterablePickler[A, List]
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle._
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds
// Same as Bad5 but without the higher-kinded type for the mapPickler.
object Good4 extends Implicits {
implicit def mapPickler[T: Pickler, S: Pickler](
implicit cbf: CanBuildFrom[Nothing, (T, S), Map[T, S]]): Pickler[Map[T, S]] =
BasicPicklers.MapPickler[T, S, Map]
implicit def iterablePickler[T: Pickler, V[_] <: Iterable[_]](implicit cbf: CanBuildFrom[Nothing, T, V[T]]): Pickler[V[T]] =
BasicPicklers.IterablePickler[T, V]
lazy val myTypeBPickler: Pickler[MyTypeB[Any]] = {
implicit object MyTypeBPickler extends Pickler[MyTypeB[Any]] {
override def pickle(v: MyTypeB[Any])(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeB[Any] = {
MyFixedTuple(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeB[Any]]]
)
???
}
}
MyTypeBPickler
}
}
package pickle
import boopickle.DefaultBasic._
// Same as Bad1 but no nested higher-kinded types.
object Good5 extends Implicits {
lazy val myTypeCPickler: Pickler[MyTypeC] = {
implicit object MyTypeCPickler extends Pickler[MyTypeC] {
override def pickle(v: MyTypeC)(implicit state: PickleState): Unit = ???
override def unpickle(implicit state: UnpickleState): MyTypeC = {
MyFixedTuple2(
state.unpickle[List[MyTypeA]],
state.unpickle[List[MyTypeC]]
)
???
}
}
MyTypeCPickler
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment