1. Introduction

Scala 3 introduced many new features to the Scala language including Extension Methods, Open Classes, Union Types, and Inline modifiers. In this tutorial,  we’ll look at another newly introduced feature, the transparent trait.

2. Type Inference Issue

Before going into the details of the transparent trait, let’s first look at a strange type inference problem:

object NonTransparent {
  trait Marker
  trait Genre { def name: String }
  object Horror extends Genre, Marker {
    override val name: String = "Horror"
  }
  object Comedy extends Genre, Marker {
    override val name: String = "Comedy"
  }
  val isScary = true
  val genre /* : Genre & Marker */ = if (isScary) Horror else Comedy
}

Here, we defined two traits Marker and Genre, where Marker is just meant to be a marker-trait and has no functional value. It’s used for only internal purposes such as code generation.

In the above code sample, the inferred type for the variable genre is an Intersection Type with Genre and Marker traits. However, it’s unnecessary to show this marker-trait in the type signature as it has no importance functionally. It’s enough, in this case, to display the type as only Genre.

In a similar way, in Scala 2, it’s generally suggested to extend the ADT case classes with Product and Serializable to get better type inference.

3. Transparent Trait

The transparent keyword is a soft keyword that can be applied to a trait. As the name suggests, it makes the trait transparent to the compiler when performing type inference.

Let’s add the modifier transparent to the Marker trait in the above sample code:

transparent trait Marker

As a result, the compiler now infers the type for the variable genre as Genre without including the type Marker.

We should note that if all the traits in the mix-in are transparent traits, then the compiler completely ignores the transparent keyword and includes all the traits in the type inference.

We should not confuse transparent traits with transparent inline methods in Scala Macros.

Note that Scala 3 treats the built-in types Product, Comparable, and Serializable as transparent. This solves the need to explicitly extend the classes with Product and Serializable to get around the type inference issue.

4. Conclusion

In this article, we looked at the newly introduced transparent trait in Scala 3. One useful real-world use for transparent traits is logging, which can be seen here.

As always, the source code for the examples is available over on GitHub.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.