Scala Implicits
Implicits let the compiler automatically supply values, conversions, or parameters that you would otherwise write explicitly. When you mark something as implicit (or given in Scala 3), the compiler finds and injects it where needed. This removes repetitive boilerplate and enables powerful patterns like type classes and extension methods.
Implicit Parameters
An implicit parameter is filled in automatically by the compiler when you omit it:
// Scala 3 style: 'using' keyword
def greet(name: String)(using prefix: String): String =
s"$prefix, $name!"
given myPrefix: String = "Hello" // 'given' makes it available implicitly
println(greet("Alice")) // Hello, Alice! (prefix supplied automatically)
println(greet("Bob")) // Hello, Bob!
println(greet("Carol")(using "Hey")) // Hey, Carol! (explicit override)
given / using in Scala 3
// Define a given instance
given ordering: Ordering[String] = Ordering.by(_.length)
def sortByRule[A](items: List[A])(using ord: Ordering[A]): List[A] =
items.sorted
val words = List("banana", "fig", "apple", "kiwi")
println(sortByRule(words)) // List(fig, kiwi, apple, banana) — sorted by length
Extension Methods (Scala 3)
Extension methods add new methods to existing types without modifying them:
extension (n: Int)
def isEven: Boolean = n % 2 == 0
def isOdd: Boolean = !n.isEven
def times(f: () => Unit): Unit = (1 to n).foreach(_ => f())
def squared: Int = n * n
println(7.isOdd) // true
println(8.isEven) // true
println(5.squared) // 25
3.times(() => println("Hello!"))
// Hello!
// Hello!
// Hello!
Extension on String
extension (s: String)
def wordCount: Int = s.split("\\s+").length
def isPalindrome: Boolean = s == s.reverse
def toTitleCase: String =
s.split(" ").map(w => w.head.toUpper + w.tail.toLowerCase).mkString(" ")
println("hello world scala".wordCount) // 3
println("racecar".isPalindrome) // true
println("the quick brown fox".toTitleCase) // The Quick Brown Fox
Implicit Conversions (Use Sparingly)
// Scala 2 style implicit conversion
implicit def intToString(n: Int): String = n.toString
// Scala 3 requires explicit import
import scala.language.implicitConversions
given Conversion[Int, String] = _.toString
val s: String = 42 // compiler inserts conversion automatically
println(s) // "42"
Implicit conversions can make code hard to follow. Use them sparingly and only in well-documented library code. Extension methods are preferred for adding methods; using parameters are preferred for dependency injection.
Type Class Pattern with given/using
// Define the type class
trait Show[A]:
def show(value: A): String
// Provide instances for specific types
given Show[Int] with
def show(n: Int): String = s"Int($n)"
given Show[String] with
def show(s: String): String = s"Str($s)"
given Show[Boolean] with
def show(b: Boolean): String = if b then "yes" else "no"
// Generic function that works with any Show instance
def display[A](value: A)(using s: Show[A]): String = s.show(value)
println(display(42)) // Int(42)
println(display("hello")) // Str(hello)
println(display(true)) // yes
summon — Accessing a given
val intShow = summon[Show[Int]]
println(intShow.show(99)) // Int(99)
// Like implicitly in Scala 2
// val intShow2 = implicitly[Show[Int]]
Implicit Search Rules
When the compiler looks for a given/implicit, it searches:
1. Current scope
2. Imported scopes
3. Companion objects of types involved
4. Inherited scopes
Priority: explicit > imported > companion object
If ambiguous → compile error
If missing → compile error
Practical: Configurable Logging
case class LogConfig(level: String, prefix: String)
given defaultConfig: LogConfig = LogConfig("INFO", "[App]")
def log(message: String)(using config: LogConfig): Unit =
println(s"${config.prefix} [${config.level}] $message")
log("Server started") // [App] [INFO] Server started
log("User logged in") // [App] [INFO] User logged in
// Override for a specific scope
{
given debugConfig: LogConfig = LogConfig("DEBUG", "[Debug]")
log("Entering function") // [Debug] [DEBUG] Entering function
}
// Outside block — back to defaultConfig
log("Back to normal") // [App] [INFO] Back to normal
