I guess this question is not strictly Avro4s-specific, but here is my problem: in the following scenario
trait Event
case class UserCreated(age: Int) extends Event
case class UserDeleted(age: Int) extends Event
I would like to be able to decode one such event based on an indication, something like
def getDecoderBasedOnType(eventName: String): Decoder[Event] =
eventName match {
case "usercreated" => Decoder[UserCreated]
case "userdeleted" => Decoder[UserDeleted]
}
This won't work because the return type of this function is
def getDecoderBasedOnType(eventName: String): Decoder[_ >: UserCreated with UserDeleted <: Event]
Is there a way to achieve my goal? Pointers for me to understand what is happening are super welcome.
This question is not Scala 3 specific.
Nothing is wrong with the return type Decoder[_ >: UserCreated with UserDeleted <: Event]
, which is a legitimate existential type.
But if you really want Decoder[Event]
, the thing is that although Decoder
could be covariant (trait Decoder[+T]
, i.e. Decoder[A] <: Decoder[B]
for A <: B
)
https://scastie.scala-lang.org/Vj9pGvRiTMaFZIwJy8Z3EA
actually as defined it is invariant (i.e. Decoder[A]
, Decoder[B]
are unrelated). But there is .map
transforming Decoder[T]
into Decoder[U]
trait Decoder[T] {
self =>
def decode(schema: Schema): Any => T
final def map[U](f: T => U): Decoder[U] = new Decoder[U] {
override def decode(schema: Schema): Any => U = { input =>
f(self.decode(schema).apply(input))
}
}
}
You can try
def getDecoderBasedOnType(eventName: String): Decoder[Event] =
eventName match {
case "usercreated" => Decoder[UserCreated].map(identity)
case "userdeleted" => Decoder[UserDeleted].map(identity)
}
https://scastie.scala-lang.org/H5vMxWfBS8SN1FryfysFBg
Contravariance vs Covariance in Scala
How to check covariant and contravariant position of an element in the function?