Transparent Traits and Classes (original) (raw)

Edit this page on GitHub

Traits are used in two roles:

  1. As mixins for other classes and traits
  2. As types of vals, defs, or parameters

Some traits are used primarily in the first role, and we usually do not want to see them in inferred types. An example is the Product trait that the compiler adds as a mixin trait to every case class or case object. In Scala 2, this parent trait sometimes makes inferred types more complicated than they should be. Example:

trait Kind
case object Var extends Kind
case object Val extends Kind
val x = Set(if condition then Val else Var)

Here, the inferred type of x is Set[Kind & Product & Serializable] whereas one would have hoped it to be Set[Kind]. The reasoning for this particular type to be inferred is as follows:

Scala 3 allows one to mark a trait or class as transparent, which means that it can be suppressed in type inference. Here's an example that follows the lines of the code above, but now with a new transparent trait S instead of Product:

transparent trait S
trait Kind
object Var extends Kind, S
object Val extends Kind, S
val x = Set(if condition then Val else Var)

Now x has inferred type Set[Kind]. The common transparent trait S does not appear in the inferred type.

In the previous example, one could also declare Kind as transparent:

The widened union type of if condition then Val else Var would then only contain the transparent traits Kind and S. In this case, the widening is not performed at all, so x would have type Set[Val | Var].

The root classes and traits Any, AnyVal, Object, and Matchable are considered to be transparent. This means that an expression such as

if condition then 1 else "hello"

will have type Int | String instead of the widened type Any.

Which Traits and Classes Are Transparent?

Traits and classes are declared transparent by adding the modifier transparent. Scala 2 traits and classes can also be declared transparent by adding a @transparentTrait annotation. This annotation is defined in scala.annotation. It will be deprecated and phased out once Scala 2/3 interoperability is no longer needed.

The following classes and traits are automatically treated as transparent:

    scala.Any
    scala.AnyVal
    scala.Matchable
    scala.Product
    java.lang.Object
    java.lang.Comparable
    java.io.Serializable

Typically, transparent types other than the root classes are traits that influence the implementation of inheriting classes and traits that are not usually used as types by themselves. Two examples from the standard collection library are:

Generally, any trait that is extended recursively is a good candidate to be declared transparent.

Rules for Inference

Transparent traits and classes can be given as explicit types as usual. But they are often elided when types are inferred. Roughly, the rules for type inference imply the following.

The precise rules are as follows: