Edit this page on GitHub

Deferred Givens

Scala 3.6 introduces a new way to implement a given definition in a trait like this:

given T = deferred

Such givens can be implemented automatically in subclasses. deferred is a new method in the scala.compiletime package, which can appear only as the right hand side of a given defined in a trait. Any class implementing that trait will provide an implementation of this given. If a definition is not provided explicitly, it will be synthesized by searching for a given of type T in the scope of the inheriting class. Specifically, the scope in which this given will be searched is the environment of that class augmented by its parameters but not containing its members (since that would lead to recursive resolutions). If an implementation is provided explicitly, it counts as an override of a concrete definition and needs an override modifier.

Deferred givens allow a clean implementation of context bounds in traits, as in the following example:

trait Sorted:
  type Element : Ord

class SortedSet[A : Ord as ord] extends Sorted:
  type Element = A

The compiler expands this to the following implementation.

trait Sorted:
  type Element
  given Ord[Element] = compiletime.deferred

class SortedSet[A](using ord: Ord[A]) extends Sorted:
  type Element = A
  override given Ord[Element] = ord

The using clause in class SortedSet provides an implementation for the deferred given in trait Sorted.

One can also provide an explicit implementation of a deferred given, as in the following example:

class SortedString[A] extends Sorted:
  type Element = String
  override given Ord[String] = ...

Note that the implementing given needs an override modifier since the deferred given in class Sorted counts as a concrete (i.e. not abstract) definition. In a sense, deferred on the right-hand side in Sorted is like a (magic, compiler-supported) macro, with the peculiarity that the macro's implementation also affects subclasses.

Abstract Givens

A given may also be an abstract member, with the restriction that it must have an explicit name. Example:

trait HasOrd[T]:
  given ord: Ord[T]

An abstract given has the form given name: Type without a right-hand side or arguments to the type.

Since Scala 3.6, abstract givens are made redundant by deferred givens. Deferred givens have better ergonomics, since they get naturally implemented in inheriting classes, so there is no longer any need for boilerplate to fill in definitions of abstract givens.

It is therefore recommended that software architectures relying on abstract givens be migrated to use deferred givens instead. Abstract givens are still supported in Scala 3.6, but will likely be deprecated and phased out over time.

In this article