arainko / ducktape

Automatic and customizable compile time transformations between similar case classes and sealed traits/enums, essentially a thing that glues your code. Scala 3 only. Or is it duct 🤔
https://arainko.github.io/ducktape/
Other
405 stars 7 forks source link

traverseCollection is not working for Map after the migration to 0.2 #155

Closed brndt closed 7 months ago

brndt commented 7 months ago

When trying to update the library version to 0.2 I have an error

    Exception in thread "zio-fiber-89" java.lang.ClassCastException: class scala.collection.immutable.$colon$colon cannot be cast to class scala.collection.immutable.Map (scala.collection.immutable.$colon$colon and scala.collection.immutable.Map are in unnamed module of loader 'app')
        at ... .ZioTransformer.zio.$anon.traverseCollection(ZioTransformer.scala:19)

Now I have traverseCollection implemented as:

def traverseCollection[A, B, AColl <: Iterable[A], BColl <: Iterable[B]](
          collection: AColl,
          transformation: A => IO[E, B]
      )(using factory: Factory[B, BColl]): IO[E, BColl] = ZIO.foreach(collection)(transformation.apply).asInstanceOf

Before the migration it was implemented in this way:

def traverseCollection[A, B, AColl[x] <: Iterable[x], BColl[x] <: Iterable[x]](
          collection: AColl[A]
      )(using
          transformer: FallibleTransformer[[A] =>> IO[E, A], A, B],
          factory: Factory[B, BColl[B]]
      ): IO[E, BColl[B]] = ZIO.foreach(collection)(transformer.transform).asInstanceOf

Any suggestion what could be the problem? I can also pass A and B objects structure if it can help.

brndt commented 7 months ago

I've created a small snippet with the error: https://scastie.scala-lang.org/zaCPhdkuTUyrzT0A8QX9KQ

arainko commented 7 months ago

Hey! Thanks for the report and the reproduction :smile: I'm afraid the asInstanceOf call working before was just a stroke of luck. The good news is that you can easily get rid of it by tinkering with the traverseCollection impl:

def traverseCollection[A, B, AColl <: Iterable[A], BColl <: Iterable[B]](
          collection: AColl,
          transformation: A => IO[E, B]
      )(using factory: Factory[B, BColl]): IO[E, BColl] = ZIO.foreach(collection)(transformation.apply).map(factory.fromSpecific)

Here's the scastie snippet but with that change applied: https://scastie.scala-lang.org/1AQtvFdXQH24JYvsQRXpAw

...and after running it it evaluates to: PlayerStats(test,test,test,Map(1 -> TournamentStats(Map(f5f746e6-3699-4c82-b3f3-cd92cf6438fc -> Stats(1,2,3,4,5))))) which I think is what you'd expect.