Scala 2.13 → Scala 3.3 LTS: Final Porting

You've crossed the bridge. Now it's time to flip the switch to Scala 3.3, the Long Term Support (LTS) version. This lesson covers the final technical hurdles and how to stabilize your project for the future.

Switching the Version

Change your scalaVersion to 3.3.1 (or the latest 3.3.x).

Real-World Example: The "TASTy" Benefit

Scala 3 uses a new intermediate format called TASTy. This allows Scala 3 to read Scala 2.13 binaries. If a library hasn't been ported to Scala 3 yet, you can often still use the 2.13 version!

// How to use a 2.13 library in a Scala 3 project
libraryDependencies += ("org.example" %% "old-library" % "1.0.0").cross(CrossVersion.for3Use2_13)

Adopting New Syntax (Without Rewriting Everything)

Scala 3 allows "Quiet Syntax" (indentation-based) but still supports braces. Don't feel pressured to rewrite your whole codebase on day one.

1. From implicit to given/using

This is the most significant conceptual change.

  • Old (2.13): implicit val ec: ExecutionContext = ...

  • New (3.3): given ec: ExecutionContext = ...

  • Old (2.13): def run(implicit ec: ExecutionContext)

  • New (3.3): def run(using ec: ExecutionContext)

Real-World Tip: Use the compiler option -rewrite -source 3-migration to let the compiler automatically convert some of your syntax.

Handling Language Changes

1. Enums

Scala 3 finally has a native enum. If you were using Enumeration or complex sealed trait hierarchies, you can now simplify them.

enum Color {
  case Red, Green, Blue
}

2. Extension Methods

Replace your old implicit class with the cleaner extension syntax.

extension (s: String)
  def isEmail: Boolean = s.contains("@")

Stabilization and Hardening

Once it compiles, the work isn't done.

  1. Check Warnings: Scala 3 is much more "chatty" about potential bugs. Treat warnings as errors.
  2. Performance Regression: In some cases, the new implicit resolution (given/using) can affect compile times. Use the -Yprofile-trace flag to find slow-compiling files.
  3. Runtime Behavior: While the bytecode is mostly compatible, always run your full integration test suite to catch edge cases in reflection or serialization libraries.

Summary

Migrating to Scala 3.3 LTS isn't just about the new features; it's about putting your project on a modern, supported foundation. By following the 2.13 bridge path, you've ensured that your migration was a series of small, manageable steps rather than one giant leap into the unknown.