My experience migrating a PlayFramework app to Scala 3

I have a small PlayFramework app (https://superintendent.app) that I just migrated 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 TypeTag, and it did correctly:

What was funny was that I prompted it to use izumi-reflect because I thought we needed the izumi-reflect library. It turns out we don't need it. We didn't even need TypeTag in the first place. 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.

SPONSORED

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