Given Instances

Given instances (or, simply, "givens") define "canonical" values of certain types that serve for synthesizing arguments to context parameters. Example:

``````trait Ord[T] {
def compare(x: T, y: T): Int
def (x: T) < (y: T) = compare(x, y) < 0
def (x: T) > (y: T) = compare(x, y) > 0
}

given intOrd as Ord[Int] {
def compare(x: Int, y: Int) =
if (x < y) -1 else if (x > y) +1 else 0
}

given listOrd[T](using ord: Ord[T]) as Ord[List[T]] {

def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match
case (Nil, Nil) => 0
case (Nil, _) => -1
case (_, Nil) => +1
case (x :: xs1, y :: ys1) =>
val fst = ord.compare(x, y)
if (fst != 0) fst else compare(xs1, ys1)
}
``````

This code defines a trait `Ord` with two given instances. `intOrd` defines a given for the type `Ord[Int]` whereas `listOrd[T]` defines givens for `Ord[List[T]]` for all types `T` that come with a given instance for `Ord[T]` themselves. The `using` clause in `listOrd` defines a condition: There must be a given of type `Ord[T]` for a given of type `List[Ord[T]]` to exist. Such conditions are expanded by the compiler to context parameters, which are explained in the next section.

Anonymous Givens

The name of a given can be left out. So the definitions of the last section can also be expressed like this:

``````given Ord[Int] { ... }
given [T](using Ord[T]) as Ord[List[T]] { ... }
``````

If the name of a given is missing, the compiler will synthesize a name from the implemented type(s).

Alias Givens

An alias can be used to define a given instance that is equal to some expression. E.g.:

``````given global as ExecutionContext = new ForkJoinPool()
``````

This creates a given `global` of type `ExecutionContext` that resolves to the right hand side `new ForkJoinPool()`. The first time `global` is accessed, a new `ForkJoinPool` is created, which is then returned for this and all subsequent accesses to `global`.

Alias givens can be anonymous, e.g.

``````given Position = enclosingTree.position
given (using outer: Context) as Context = outer.withOwner(currentOwner)
``````

An alias given can have type parameters and implicit parameters just like any other given, but it can only implement a single type.

Given Whitebox Macro Instances

An `inline` alias given can be marked as a whitebox macro by writing `_ <:` in front of the implemented type. Example:

``````inline given mkAnnotations[A, T] as _ <: Annotations[A, T] = \${
// code producing a value of a subtype of Annotations
}
``````

The type of an application of `mkAnnotations` is the type of its right hand side, which can be a proper subtype of the declared result type `Annotations[A, T]`.

Given Instance Initialization

A given instance without type or context parameters is initialized on-demand, the first time it is accessed. If a given has type or context parameters, a fresh instance is created for each reference.

Syntax

Here is the new syntax for given instances, seen as a delta from the standard context free syntax of Scala 3.

``````TmplDef           ::=  ...
|   ‘given’ GivenDef
GivenDef          ::=  [GivenSig] [‘_’ ‘<:’] Type ‘=’ Expr
|   [GivenSig] ConstrApp {‘,’ ConstrApp } [TemplateBody]
GivenSig          ::=  [id] [DefTypeParamClause] {UsingParamClause} ‘as’
``````