Here’s a proposal to add (untagged) union types to Scala 3. A union type
A | B is the dual of an intersection type
A & B.
Here’s a link to the Dotty doc page for union types.
There are several good reasons for introducing union types:
- They are algebraically the dual of intersection types
- With both unions and intersections, Scala’s subtype hierarchy becomes a lattice.
- They fix the problem of Scala’s least upper bounds. Least upper bounds arise in a number of situations, such as when computing the type of an if-then-else or match expression, or when inferring type arguments to functions. in Scala-2 least upper bounds were computed indirectly as intersections of dominator types. The problem with this approach is that the results of these computations could be infinite, which meant they had to be approximated with ad-hoc hacks, and even the approximated results could be huge, spanning many pages of output in some error messages. Union types avoid these “exploding lubs”.
- They provide added modelling power, which is useful notably for Scala.js (Scala.js has its own emulation of union types which could be replaced by this proposal.
- They provide a good intermediate step if we want to model null safety.
The present design is kept very conservative in what concerns type inference. In essence, union types must be explicitly declared in most situations (the doc page contains a discussion of this). The reasons for being conservative are
- Better compatibility with Scala 2. If we start to infer union types in many situations where none were inferred before, this will change type inference and will also inevitably break some programs that compiled before.
- Avoid potential blowups in compile-time.
- We can always be less more expressive in future versions of the language. Going in the other direction is not so easy.
This proposal is open for discussion in the community and will be discussed in our next SIP meeting, where we’ll take all your feedback into account for the approval/dismissal of this feature.