Skip to content
AgileLogics
6 min read

Givens and Using Clauses

Contextual abstractions let the compiler pass values for you. A given defines a value available in a context; a using parameter asks for one.

case class Config(currency: String, taxRate: Double)

def priceWithTax(net: Double)(using config: Config): String =
  f"${net * (1 + config.taxRate)}%.2f ${config.currency}"

def invoiceLine(item: String, net: Double)(using Config): String =
  s"$item: ${priceWithTax(net)}"

@main def givens(): Unit =
  given Config = Config("EUR", 0.2)
  println(invoiceLine("Keyboard", 89))
  println(invoiceLine("Monitor", 249.99))
  println(priceWithTax(100)(using Config("GBP", 0.0)))
Keyboard: 106.80 EUR
Monitor: 299.99 EUR
100.00 GBP
  • (using config: Config) — the compiler fills this parameter with a given Config in scope.
  • invoiceLine passes it on implicitly: its own using Config is in scope when it calls priceWithTax. The configuration flows through the call chain without being repeated at every call.
  • You can still pass a value explicitly with (using ...).

Where the compiler looks

The compiler finds givens in the current scope (including imports) and in the companion objects of the types involved. Givens are imported explicitly with import Module.given, so it's always clear where they come from.

object Formats:
  given Ordering[String] = Ordering.by(_.length)

@main def importingGivens(): Unit =
  val words = List("banana", "fig", "cherry", "kiwi")
  println(words.sorted)
  import Formats.given
  println(words.sorted)
List(banana, cherry, fig, kiwi)
List(fig, kiwi, banana, cherry)

sorted takes a using Ordering[A]. The default Ordering[String] is alphabetical; after importing the given from Formats, the local one wins and words are sorted by length.

Good uses

  • Type class instances (next lesson) — by far the most common use.
  • Context that many functions need: an execution context, a configuration, a database transaction.

Avoid givens for ordinary values like Int or String — the more specific the type, the safer implicit passing is.

(Scala 2 used implicit val and implicit parameters for the same ideas — you'll see them in older code and libraries.)