My experience migrating a PlayFramework app to Scala 3

I have a small PlayFramework app (https://superintendent.app), which was on Scala 2. I've decided to migrate this app to Scala 3. Here are my learnings:

The goods

  1. Scala 2 syntax is still valid in Scala 3. Basically, 95% of the code still works as-is.
  2. Cross-publishing one of my libraries to work with Scala 3 took maybe 15 minutes. SBT seems stable and robust these days.
  3. I used TypeTag, which has been removed in Scala 3. I've randomly decided to tell AI to rewrite it without rewriting it without TypeTag, and it did correctly:

I prompted it to use izumi-reflect because I thought we needed it. It turns out we don't need it, and AI did it correctly. That AI moment was magical.

The obstacles

  1. The unapply of a case class has been effectively removed.

It took me a while to find a replacement (link):

  object Tuples:
    def to[A <: Product](value: A)(
      using mirror: Mirror.ProductOf[A]
    ): mirror.MirroredElemTypes = Tuple.fromProductTyped(value)

    def from[A](value: Product)(
      using
      mirror: Mirror.ProductOf[A],
      ev: value.type <:< mirror.MirroredElemTypes
    ): A = mirror.fromProduct(value)

 // Tuples.to[YourCaseClass] is equivalent to YourCaseClass.unapply.
 //
 // If your case class has only 1 parameter, then Tuples.to[YourCaseClass] would output a tuple of one. This is the only difference.
  1. Enum isn't as flexible nor powerful as Sealed Abstract Class

Obviously, but this took me maybe an hour to rewrite the implicits that we had for the original Sealed Abstract Class.

extension doesn't work with Enum, so I had to flip the method from an implicit conversion to a regular method that took an enum value as the first parameter.

I've also learned that we cannot overwrite name if our enum extends the Java's Enum.

  1. scala.reflect.runtime has been mostly removed.

ClassTag still exists. This enables us to use Java's reflection.

However, TypeTag has been removed. This means we cannot utilize knownDirectSubclasses, for example.

izumi-reflect seems like a good replacement but you will have to learn the library. I didn't because it turned out I don't need it. Java's reflection suffices for my need.

Subscribe to tanin

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe