Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Given examples

In Scala 3 (formerly known as Dotty), the given and using clauses represent a sophisticated evolution of Scala's implicits feature, making it more explicit and easier to reason about. These features are part of Scala's type class support, allowing for more expressive and type-safe code. Let's dive into a few examples to understand how given and using work.

Example 1: Basic Type Class

A type class is a sort of interface that defines some behavior. Unlike traditional interfaces, type classes can be "attached" to classes after they've been defined. Let's define a simple JsonSerializer type class and then use given and using to serialize objects to JSON.

Define the Type Class

trait JsonSerializer[T] {
  def serialize(value: T): String
}

Implement the Type Class

given JsonSerializer[String] with {
  def serialize(value: String): String = s""""$value""""
}

given JsonSerializer[Int] with {
  def serialize(value: Int): String = value.toString
}

Use the Type Class

def toJson[T](value: T)(using serializer: JsonSerializer[T]): String = {
  serializer.serialize(value)
}

println(toJson("hello"))  // Output: "hello"
println(toJson(123))      // Output: 123

Example 2: Contextual Abstractions with using Parameters

Sometimes, you might want to pass additional parameters contextually without cluttering the method signature for every call. This is where using shines.

Define a Context

case class RequestContext(userId: String)

given RequestContext = RequestContext("user123")

A Method that Requires Context

def getUser(using ctx: RequestContext): String = {
  s"Fetching data for user: ${ctx.userId}"
}

println(getUser)  // Output: Fetching data for user: user123

Example 3: Generic Programming with given

You can also use given instances for generic programming, such as defining a generic sum function for numeric types.

Numeric Type Class

trait Numeric[T] {
  def plus(x: T, y: T): T
  def zero: T
}

given Numeric[Int] with {
  def plus(x: Int, y: Int): Int = x + y
  def zero: Int = 0
}

Generic Sum Function

def sum[T](items: List[T])(using numeric: Numeric[T]): T = {
  items.foldLeft(numeric.zero)(numeric.plus)
}

println(sum(List(1, 2, 3)))  // Output: 6