Reputation: 1868
I am having problems with the following:
sealed trait Expression[T] {
def doSomething: Either[String, T]
}
case class Literal(s: String) extends Expression[String] {
def soSomething = Right(s)
}
object Expression{
implicit def encoder[T: Encoder]: Encoder[Expression[T]]
implicit def decoder[T: Decoder]: Decoder[Expression[T]]
}
I see the several errors:
could not find lazy implicit value of type io.circe.generic.extras.decoding.ConfiguredDecoder[Expression[T]]
not enough arguments for method deriveDecoder: (implicit decode: shapeless.Lazy[ConfiguredDecoder[Expression[T]]])
Obviously I am missing an implicit but cant see what I have missed from the circe examples I have followed.
Could anyone help or point me at a better way of doing this?
Cheers
Terry
EDIT
The solution provided below worked great but I am extending the ADT to cover further cases - I cannot get the following to compile:
case class Equals[F[_] <: Expression[_], T](left: F[T], right: F[T]) extends Expression[Boolean]{
def doIt: Either[String, Boolean] = ???
}
object Equals {
implicit def encoder[F[_] <: Expression[_], T](implicit FT: encoder[F[T]]): Encoder[Equals[F, T]] = deriveEncoder
}
I suspect I am not picking up the implicit Encoder for Expression[_] I have tried importing this in the Equals object but that does not help. Any further advice would help including advice how to debug these issues.
Upvotes: 1
Views: 1340
Reputation: 51683
The implicits
implicit def encoder[T: Encoder]: Encoder[Expression[T]]
implicit def decoder[T: Decoder]: Decoder[Expression[T]]
mean that in order to generate codecs Circe must know what representation Expression[T]
has for arbitrary T
(and then to generate codecs for Expression[T]
Circe can use codecs for children, codecs for T
etc.). And what should the representation be?
implicitly[Generic.Aux[Expression[T], ???]]
(for simplicity I write Generic
rather than LabelledGeneric
).
Expression[String]
has a child Literal
, so
implicitly[Generic.Aux[Expression[String], Literal :+: CNil]]
But e.g. Expression[Int]
doesn't have children
implicitly[Generic[Expression[Int]]] // doesn't compile, although I guess it could be: Generic.Aux[Expression[Int], CNil]
You just know that
implicitly[Generic.Aux[Expression[_], Literal :+: CNil]]
So try unconditional implicits (and implicits for existential if you need)
object Literal {
implicit val encoder: Encoder[Literal] = deriveEncoder
implicit val decoder: Decoder[Literal] = deriveDecoder
}
// optional, you can remove this if you don't need decode[Expression[_]]("...")
trait LowPriorityExpression {
implicit def encoder1 : Encoder[Expression[_]] = deriveEncoder
implicit def decoder1: Decoder[Expression[_]] = deriveDecoder
}
object Expression extends LowPriorityExpression {
implicit def encoder: Encoder[Expression[String]] = deriveEncoder
implicit def decoder: Decoder[Expression[String]] = deriveDecoder
}
Then
Literal("abc").asJson.noSpaces //{"s":"abc"}
(Literal("abc"): Expression[String]).asJson.noSpaces //{"Literal":{"s":"abc"}}
// (Literal("abc"): Expression[_]).asJson.noSpaces // doesn't compile without io.circe.generic.auto._
decode[Literal]("""{"s":"abc"}""") // Right(Literal(abc))
decode[Expression[String]]("""{"Literal":{"s":"abc"}}""") // Right(Literal(abc))
decode[Expression[_]]("""{"Literal":{"s":"abc"}}""") // Right(Literal(abc))
// decode[Expression[Int]]("""{"Literal":{"s":"abc"}}""") // doesn't compile, expected
See also
How to use circe with generic case class that extends a sealed trait
https://github.com/circe/circe/issues/1353
I noticed that with auto
insted of semiauto
codecs for Expression[T]
are resolved a little better. So I looked with reify
how they are resolved and defined these codecs manually. So we are not using now auto
approach, we are using semiauto
approach and re-using some of auto
functionality explicitly in one place.
import io.circe.generic.encoding.DerivedAsObjectEncoder
import io.circe.generic.semiauto
import io.circe.generic.auto
import io.circe.generic.decoding.DerivedDecoder
import io.circe.{Decoder, Encoder}
sealed trait Expression[T] {
def doSomething: Either[String, T]
}
case class Literal(s: String) extends Expression[String] {
override def doSomething: Either[String, String] = Right(s)
}
object Literal {
implicit val encoder: Encoder[Literal] = semiauto.deriveEncoder
implicit val decoder: Decoder[Literal] = semiauto.deriveDecoder
}
case class Literal1(i: Int) extends Expression[Int] {
override def doSomething: Either[String, Int] = Right(i)
}
object Literal1 {
implicit val encoder: Encoder[Literal1] = semiauto.deriveEncoder
implicit val decoder: Decoder[Literal1] = semiauto.deriveDecoder
}
case class Literal2[T](t: T) extends Expression[T] {
override def doSomething: Either[String, T] = Right(t)
}
object Literal2 {
implicit def encoder[T: Encoder]: Encoder[Literal2[T]] = semiauto.deriveEncoder
implicit def decoder[T: Decoder]: Decoder[Literal2[T]] = semiauto.deriveDecoder
}
case class Equals[F[_] <: Expression[_], T](left: F[T], right: F[T]) extends Expression[Boolean] {
override def doSomething: Either[String, Boolean] = ???
}
object Equals {
implicit def encoder[F[_] <: Expression[_], T](implicit
FT: Encoder[F[T]]
): Encoder[Equals[F, T]] = semiauto.deriveEncoder
implicit def decoder[F[_] <: Expression[_], T](implicit
FT: Decoder[F[T]]
): Decoder[Equals[F, T]] = semiauto.deriveDecoder
}
object Expression {
implicit def encoder[T](implicit
ev: DerivedAsObjectEncoder[Expression[T]]
): Encoder[Expression[T]] = Encoder.importedEncoder(auto.exportEncoder)
implicit def decoder[T](implicit
ev: DerivedDecoder[Expression[T]]
): Decoder[Expression[T]] = Decoder.importedDecoder(auto.exportDecoder)
}
// everything compiles
implicitly[Encoder[Literal]]
implicitly[Decoder[Literal]]
implicitly[Encoder[Literal1]]
implicitly[Decoder[Literal1]]
implicitly[Encoder[Expression[String]]]
implicitly[Encoder[Expression[Int]]]
implicitly[Decoder[Expression[String]]]
implicitly[Decoder[Expression[Int]]]
implicitly[Encoder[Equals[Expression, Int]]]
implicitly[Encoder[Equals[Expression, String]]]
implicitly[Decoder[Equals[Expression, Int]]]
implicitly[Decoder[Equals[Expression, String]]]
implicitly[Encoder[Equals[Literal2, Int]]]
implicitly[Encoder[Equals[Literal2, String]]]
implicitly[Decoder[Equals[Literal2, Int]]]
implicitly[Decoder[Equals[Literal2, String]]]
But implicitly[Decoder[Expression[Boolean]]]
and implicitly[Encoder[Expression[Boolean]]]
still don't compile even with auto
. I'm afraid we come here to the limits of Scala 2 type system (and Shapeless 2).
import shapeless.{Generic, :+:, CNil, Generic1, the}
implicitly[Generic.Aux[Expression[String], Literal :+: Literal2[String] :+: CNil]]
implicitly[Generic.Aux[Expression[Int], Literal1 :+: Literal2[Int] :+: CNil]]
//implicitly[Generic[Expression[Boolean]] // doesn't compile
//implicitly[Generic[Expression[_]]] // doesn't compile
//kinds of the type arguments (F[_],T) do not conform to the expected
//kinds of the type parameters (type F,type T) in class Equals.
//F[_]'s type parameters do not match type F's expected parameters:
//type F has 1 type parameter, but type F has 1
type T
implicitly[Generic.Aux[Expression[T], Literal2[T] :+: CNil]]
trait Always[F[_]]
object Always {
implicit def mkAlways[F[_]]: Always[F] = new Always[F] {}
}
val gen = the[Generic1[Expression, Always]]
implicitly[gen.R[T] =:= (Literal2[T] :+: CNil)]
What could the representation of Expression[Boolean]
be?
implicitly[Generic.Aux[Expression[Boolean], ???]]
Should it be (Equals[F, _] forSome {type F[_]}) :: Literal2[Boolean] :+: CNil
?
Or Equals[λ[T => Expression[_]], _] :: Literal2[Boolean] :+: CNil
aka Equals[({type λ[_] = Expression[_]})#λ, _] :: Literal2[Boolean] :+: CNil
?
In Scala 3 it's
(Literal, Literal1, Literal2[Boolean], Equals[[_] =>> Expression[?], Any])
aka Literal *: Literal1 *: Literal2[Boolean] *: Equals[[_] =>> Expression[?], Any] *: EmptyTuple
import scala.deriving.*
val exprStrMirror = summon[Mirror.SumOf[Expression[String]]]
summon[exprStrMirror.MirroredElemTypes =:= (Literal, Literal1, Literal2[String], Equals[[_] =>> Expression[?], Any])]
val exprIntMirror = summon[Mirror.SumOf[Expression[Int]]]
summon[exprIntMirror.MirroredElemTypes =:= (Literal, Literal1, Literal2[Int], Equals[[_] =>> Expression[?], Any])]
val exprBoolMirror = summon[Mirror.SumOf[Expression[Boolean]]]
summon[exprBoolMirror.MirroredElemTypes =:= (Literal, Literal1, Literal2[Boolean], Equals[[_] =>> Expression[?], Any])]
type SumOfK1[F[_]] = Mirror.Sum { type MirroredType[T] = F[T] }
val exprMirror = summon[SumOfK1[Expression]]
summon[exprMirror.MirroredElemTypes[T] =:= (Literal, Literal1, Literal2[T], Equals[[_] =>> Expression[?], Any])]
https://scastie.scala-lang.org/DmytroMitin/jrkBc5lkS1KDQO2U6uMt3Q/1
Actually, it's funny. If we have at least one generic case class (Literal2[T]
) then the original code compiles (probably my manual codecs stolen from auto
were incorrect in some cases and also Circe rely not completely on Shapeless represenations)
https://scastie.scala-lang.org/DmytroMitin/m7QZp29yQ3CLeQjOnm3Avw
If we remove the generic case class the code doesn't compile
https://scastie.scala-lang.org/DmytroMitin/m7QZp29yQ3CLeQjOnm3Avw/2
import io.circe.generic.semiauto
import io.circe.{Decoder, Encoder}
sealed trait Expression[T] {
def doSomething: Either[String, T]
}
case class Literal(s: String) extends Expression[String] {
override def doSomething: Either[String, String] = Right(s)
}
object Literal {
implicit val encoder: Encoder[Literal] = semiauto.deriveEncoder
implicit val decoder: Decoder[Literal] = semiauto.deriveDecoder
}
// !!!
case class Literal2[T](t: T) extends Expression[T] {
override def doSomething: Either[String, T] = Right(t)
}
object Literal2 {
implicit def encoder[T: Encoder]: Encoder[Literal2[T]] = semiauto.deriveEncoder
implicit def decoder[T: Decoder]: Decoder[Literal2[T]] = semiauto.deriveDecoder
}
case class Equals[F[_] <: Expression[_], T](left: F[T], right: F[T]) extends Expression[Boolean] {
override def doSomething: Either[String, Boolean] = ???
}
object Equals {
implicit def encoder[F[_] <: Expression[_], T](implicit FT: Encoder[F[T]]): Encoder[Equals[F, T]] = semiauto.deriveEncoder
implicit def decoder[F[_] <: Expression[_], T](implicit FT: Decoder[F[T]]): Decoder[Equals[F, T]] = semiauto.deriveDecoder
}
object Expression {
implicit def decoder[T: Decoder]: Decoder[Expression[T]] = semiauto.deriveDecoder
implicit def encoder[T: Encoder]: Encoder[Expression[T]] = semiauto.deriveEncoder
}
implicitly[Encoder[Literal]]
implicitly[Decoder[Literal]]
implicitly[Encoder[Expression[String]]]
implicitly[Encoder[Expression[Int]]]
implicitly[Decoder[Expression[String]]]
implicitly[Decoder[Expression[Int]]]
implicitly[Encoder[Equals[Expression, Int]]]
implicitly[Encoder[Equals[Expression, String]]]
implicitly[Decoder[Equals[Expression, Int]]]
implicitly[Decoder[Equals[Expression, String]]]
implicitly[Encoder[Equals[Literal2, Int]]]
implicitly[Encoder[Equals[Literal2, String]]]
implicitly[Decoder[Equals[Literal2, Int]]]
implicitly[Decoder[Equals[Literal2, String]]]
implicitly[Encoder[Expression[Boolean]]]
implicitly[Decoder[Expression[Boolean]]]
(Let's call this code (*) for the below purpose.)
I removed temporarily all macros but one and with -Ymacro-debug-lite
, -Xlog-implicits
switched on it produces macro expansion has failed: Sealed trait Expression[T] has no case class subtypes
so obviously it's a Circe bug
import io.circe.generic.semiauto
import io.circe.{Decoder, Encoder}
sealed trait Expression[T] {
def doSomething: Either[String, T]
}
case class Literal(s: String) extends Expression[String] {
override def doSomething: Either[String, String] = Right(s)
}
object Literal {
implicit val encoder: Encoder[Literal] = Encoder.forProduct1("s")(_.s)
implicit val decoder: Decoder[Literal] = Decoder.forProduct1("s")(Literal.apply)
}
case class Equals[F[_] <: Expression[_], T](left: F[T], right: F[T]) extends Expression[Boolean] {
override def doSomething: Either[String, Boolean] = ???
}
object Equals {
implicit def encoder[F[_] <: Expression[_], T](implicit FT: Encoder[F[T]]): Encoder[Equals[F, T]] =
Encoder.forProduct2("left", "right")(e => (e.left, e.right))
implicit def decoder[F[_] <: Expression[_], T](implicit FT: Decoder[F[T]]): Decoder[Equals[F, T]] =
Decoder.forProduct2("left", "right")(Equals.apply _)
}
object Expression {
implicit def decoder[T: Decoder]: Decoder[Expression[T]] = semiauto.deriveDecoder[Expression[T]] /*!!!*/
// implicit def encoder[T: Encoder]: Encoder[Expression[T]] = semiauto.deriveEncoder
}
Actually, Sealed trait Expression[T] has no case class subtypes
comes from Shapeless
sealed trait Expression[T]
case class Literal(s: String) extends Expression[String]
// case class Literal2[T](t: T) extends Expression[T]
case class Equals[F[_] <: Expression[_], T](left: F[T], right: F[T]) extends Expression[Boolean]
type T
implicitly[Generic[Expression[T]]]//macro expansion has failed: Sealed trait Expression[T] has no case class subtypes
The reasons are the same
sealed trait Expression[T]
case class Literal(s: String) extends Expression[String]
case class Literal2[T](t: T) extends Expression[T]
case class Equals[F[_] <: Expression[_], T](left: F[T], right: F[T]) extends Expression[Boolean]
implicitly[Generic.Aux[Expression[String], Literal :+: Literal2[String] :+: CNil]]
// implicitly[Generic[Expression[Boolean]]] // doesn't compile, kinds of the type arguments (F[_],T) do not conform to the expected kinds of the type parameters (type F,type T) in class Equals. F[_]'s type parameters do not match type F's expected parameters: type F has 1 type parameter, but type F has 1
type T
implicitly[Generic.Aux[Expression[T], Literal2[T] :+: CNil]]
Shapeless thinks that representation of Expression[T]
is Literal2[T] :+: CNil
(and doesn't include Literal
and Equals
) and without Literal2
the representation is empty.
Actually, it's not so good that Shapeless doesn't include Literal
and Equals
into the representation of Expression[T]
. Although the code (*) above compiles, it fails at runtime (throws exception MatchError
or produces Left
)
Literal("a").asJson.noSpaces
Literal2[Int](1).asJson.noSpaces
Equals[Literal2, Boolean](Literal2(true), Literal2(false)).asJson.noSpaces
//(Literal("a"): Expression[String]).asJson.noSpaces//MatchError
(Literal2[Int](1): Expression[Int]).asJson.noSpaces
//(Equals[Literal2, Boolean](Literal2(true), Literal2(false)): Expression[Boolean]).asJson.noSpaces//MatchError
decode[Literal]("""{"s":"a"}""")
decode[Literal2[Int]]("""{"t":1}""")
decode[Equals[Literal2, Boolean]]("""{"left":{"t":true},"right":{"t":false}}""")
decode[Expression[String]]("""{"Literal":{"s":"a"}}""")//Left, CNil should never happen
decode[Expression[Int]]("""{"Literal2":{"t":1}}""")
decode[Expression[Boolean]]("""{"Equals":{"left":{"Literal2":{"t":true}},"right":{"Literal2":{"t":false}}}}""")//Left, CNil should never happen
https://scastie.scala-lang.org/DmytroMitin/m7QZp29yQ3CLeQjOnm3Avw/4
A workaround is to define codecs for Expression[T]
manually
implicit def decoder[T: Decoder]: Decoder[Expression[T]] = Decoder.instance {
def readExpr(c: HCursor): Result[Expression[T]] =
c.get[Literal]("Literal").asInstanceOf[Result[Expression[T]]].orElse(
c.get[Literal2[T]]("Literal2").orElse {
def readEquals(fieldName: String): Result[Expression[T]] =
c.downField("Equals")
.downField(fieldName)
.success
.toRight(DecodingFailure(Reason.CustomReason(s"can't read Equals.$fieldName"), c))
.flatMap(readExpr)
for {
l <- readEquals("left")
r <- readEquals("right")
} yield new Equals(l, r).asInstanceOf[Expression[T]]
}
)
readExpr
}
implicit def encoder[T: Encoder]: Encoder[Expression[T]] = Encoder.instance {
case expr@Literal(_) => Json.obj("Literal" -> expr.asJson)
case expr@Literal2(_) => Json.obj("Literal2" -> expr.asJson)
case Equals(l, r) => Json.obj("Equals" ->
Json.obj(
"left" -> l.asInstanceOf[Expression[T]].asJson,
"right" -> r.asInstanceOf[Expression[T]].asJson
)
)
}
https://scastie.scala-lang.org/DmytroMitin/m7QZp29yQ3CLeQjOnm3Avw/8
I understood how to fix issues with failing at runtime (throwing MatchError
or producing Left
). We should replace
object Expression {
implicit def decoder[T: Decoder]: Decoder[Expression[T]] = semiauto.deriveDecoder
implicit def encoder[T: Encoder]: Encoder[Expression[T]] = semiauto.deriveEncoder
}
with
object Expression {
implicit def decoder[T](implicit
ev: DerivedDecoder[Expression[T]]
): Decoder[Expression[T]] = semiauto.deriveDecoder /*ev*/
implicit def encoder[T](implicit
ev: DerivedAsObjectEncoder[Expression[T]]
): Encoder[Expression[T]] = semiauto.deriveEncoder /*ev*/
}
I just added the implicit parameters DerivedDecoder[Expression[T]]
/ DerivedAsObjectEncoder[Expression[T]]
of semiauto.deriveDecoder
/deriveEncoder
to def decoder[T]
/def encoder[T]
.
Formerly these implicit parameters were resolved here, at the definition site of def decoder[T]
, def encoder[T]
i.e. for generic T
the representation of Expression[T]
was Literal2[T] :+: CNil
and this failed for Literal
. Now these implicit parameters will be resolved at the call site of def decoder[T]
, def encoder[T]
i.e. for T=String
the representation of Expression[String]
will be Literal :+: Literal2[String] :+: CNil
. (This is similar to the difference implicitly[X]
vs. (implicit x: X)
.)
(I guess it would be better if in Circe semiauto.deriveDecoder
/deriveEncoder
were macros making a user add the implicit parameters to the method when necessary.)
The question remains with type F has 1 type parameter, but type F has 1
i.e. Boolean
case.
https://scastie.scala-lang.org/DmytroMitin/m7QZp29yQ3CLeQjOnm3Avw/11
I suspect that Shapeless calculates Generic
for Expression[Boolean]
incorrectly so that there are invalid Equals[_[_] <: Expression[_], _]
in the represenation Equals[_[_] <: Expression[_], _] :+: Literal2[Boolean] :+: CNil
and Generic
instance
// Generic.instance[Expression[Boolean], Equals[_[_] <: Expression[_], _] :+: Literal2[Boolean] :+: CNil](((p: Expression[Boolean]) => Coproduct.unsafeMkCoproduct(p: @_root_.scala.unchecked match {
// case (_: Equals[_[_] <: Expression[_], _]) => 0
// case (_: Literal2[Boolean]) => 1
// }, p).asInstanceOf[Equals[_[_] <: Expression[_], _] :+: Literal2[Boolean] :+: CNil]), ((x1) => Coproduct.unsafeGet(x1).asInstanceOf[Expression[Boolean]]))
But even if we fix Generic
so that it will produce for example Equals2 :+: Literal2[Boolean] :+: CNil
type Equals2 = Equals[F, _] forSome {type F[_] <: Expression[_]}
// type Equals2 = Equals[Const[Expression[_]]#λ, _]
implicit val boolExprGeneric: Generic.Aux[Expression[Boolean], Equals2 :+: Literal2[Boolean] :+: CNil] =
Generic.instance[Expression[Boolean], Equals2 :+: Literal2[Boolean] :+: CNil](
(p: Expression[Boolean]) => Coproduct.unsafeMkCoproduct(
(p: @unchecked) match {
case _: Equals2 => 0
case _: Literal2[Boolean] => 1
},
p
).asInstanceOf[Equals2 :+: Literal2[Boolean] :+: CNil],
x => Coproduct.unsafeGet(x).asInstanceOf[Expression[Boolean]]
)
how will we define instances of Encoder
/Decoder
for existential Equals2
?
Upvotes: 2