Scala
Home > Blog> Article

What's new in Scala 3

Scala 3

Scala 3 overview

The exciting new version of Scala 3 brings many improvements and new features. Here’s a short digest for all those who are still unfamiliar with the changes and improvements that are coming in Dotty / Scala 3. Besides greatly improved type inference, the Scala 3 type system also offers many new features, giving you powerful tools to statically express invariants in the types

1. Intersections and unions

Two new features in Scala 3’s type system are intersection and union types. They embrace set theory more explicitly to improve the soundness of the type system, where a type can be considered a set and the instances of it are the members of the set.

Union types

A union type A | B represents a type that has values of type A or B at a given time. A pattern match must be performed at the point of usage to extract the exact type.

val a: A | B = new A()
val b: A | B = new B()

They are commutative, so A | B is the same as B | A.

Intersection types

An intersection type A & B represents a type that has values of type A and B at the same time.

trait TwitterPost

trait InstagramPost

def shareOnTwitter(twitter: TwitterPost)

def shareOnInstagram(instagram: InstagramPost)

val both: TwitterPost & InstagramPost =  new TwitterPost with InstagramPost

shareOnTwitter(both) // A & B  <: A 
shareOnInstagram(both) // A & B  <: B
  • Intersection types are commutative, i.e A & B is same as B & A
  • Given any types A and B , A & B is a sub type for both A and B
  • Given a co-variant type C then C[A & B] <: C[A] & C[B]

2. Enums

Scala 3 adds support for "enums", which are to sealed traits like case classes were to classes. That is, enums cut down on the boilerplate required to use the "sealed trait" pattern for modeling so-called sum types, in a fashion very similar to how case classes cut down on the boilerplate required to use classes to model so-called product types.

enum Direction:
  case North extends Direction
  case South extends Direction
  case East extends Direction
  case West extends Direction

Similarly, we can add instance data to the enumerated instances:

enum Weekday(val index: Int):
  case Mon   extends Weekday(0)
  case Tue   extends Weekday(1)
  case Wed   extends Weekday(2)
  case Thu   extends Weekday(3)
  case Fri   extends Weekday(4)
  case Sat   extends Weekday(5)
  case Sun   extends Weekday(6)

3. Trait parameters

As you know, in scala 2 traits cannot have parameters; we have abstract classes for that. However, abstract classes cannot be mixed into different parts of the class hierarchy. Well, now the traits are getting parameters too, which means syntax like this:

trait Foo(val s: String) {
  ...
}

Of course, as traits can take parameters now and as we know that multiple traits can be mixed in hierarchy, this feature could have resulted in ambiguities. To prevent this, Scala has laid the following rules and anything other than that is treated as illegal

  • If a class C extends a parameterized trait T, and its superclass does not, C must pass arguments to T.
  • If a class C extends a parameterized trait T, and its superclass does as well, C must not pass arguments to T.
  • Traits must never pass arguments to parent traits.

4 Type lambdas

Scala 3 introduces full language support for type lambdas without having to resort to ugly boilerplate or external libraries. Let’s take a popular use case where F[_] is needed, but we want to pass a type constructor that takes two types (such as Map or Either), or in other words, we want to pass (﹡ → ﹡) → ﹡ where ﹡ → ﹡is needed.

Instead of having to define a type lambda like this:

({ type T[A] = Map[Int, A] }) #T

We will be able to simply say

[A] => Map[Int, A]

Others

Here are some additional features and improvements that were included in scala 3

Polymorphic function types

Like with dependent function types, Scala 2 supported methods that allow type parameters, but did not allow programmers to abstract over those methods. In Scala 3, polymorphic function types like [A] => List[A] => List[A] can abstract over functions that take type arguments in addition to their value arguments.

Multiversal equality:

Compiler will now match the types when comparing values and fail the compilation if there’s a mismatch, e.g. “foo” == 123. We can already model this via type classes (it’s actually done in several libraries), but with Scala 3 we’re getting the native language support.

Type-classes

Scala 3 introduces direct support for typeclasses using contextual features of the language. Typeclasses provide a way to abstract over similar data types, without having to change the inheritance hierarchy of those data types, providing the power of "mixin" interfaces, but with additional flexibility that plays well with third-party data types.

Opaque Types:

Hide implementation details behind opaque type aliases without paying for it in performance! Opaque types supersede value classes and allow you to set up an abstraction barrier without causing additional boxing overhead.

Null safety:

This is based on the union types feature, which allows us to define the result type of scary operations that can throw a null pointer exception (useful for interoperability with Java) as Foo | null.

Creator Applications

Scala 3 introduces creator applications, which is a concise way to create instances of a class even if it does not have an apply method in its companion object.

Extension clauses:

These will basically be a replacement for implicit classes, e.g. extension StringOps for String { … }, but I didn’t dig too deep into this yet. Take a look at this PR if you want to find out more.

Optional Braces

Scala 3 makes braces optional (!). This new Python-esque syntax helps ensure good indentation, as well as reducing the verbosity and visual noise of Scala code

New Control flow syntax

Scala 3 adds new syntax for control operators, allowing you to omit parentheses that would have been required under Scala 2.x syntax. This makes the language more uniform (as parentheses were not required for guards in conditionals, for example), and modernizes the syntax of the language.

Resources

Ludovic TEMGOUA

Ludovic TEMGOUA

Software Developer

I am a Software Developer, Open Source enthusiast and Freelancer. I am passionate about Scala, Microservices & Full Stack Web Development. I'm open for Freelance and Student mentoring.

Phone: +237 699-131-434Email: [email protected]