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