scalaadvanced
Automatic Given Instance Derivation
Derive given instances for product and sum types using Scala 3 derives keyword and Mirror.
scalaPress ⌘/Ctrl + Shift + C to copy
import scala.deriving.Mirror
import scala.compiletime.{erasedValue, summonInline, constValueTuple}
// Type class
trait Describe[T]:
def describe(value: T): String
object Describe:
// Primitives
given Describe[Int] with
def describe(value: Int): String = s"Int($value)"
given Describe[String] with
def describe(value: String): String = s"String(\"$value\")"
given Describe[Boolean] with
def describe(value: Boolean): String = s"Boolean($value)"
given Describe[Double] with
def describe(value: Double): String = f"Double($value%.2f)"
// For Option
given [T: Describe]: Describe[Option[T]] with
def describe(value: Option[T]): String = value match
case Some(v) => s"Some(${summon[Describe[T]].describe(v)})"
case None => "None"
// For List
given [T: Describe]: Describe[List[T]] with
def describe(value: List[T]): String =
val d = summon[Describe[T]]
value.map(d.describe).mkString("List(", ", ", ")")
// Helper for product types
inline def describeProduct[T <: Tuple](values: T, index: Int = 0): List[String] =
inline values match
case _: EmptyTuple => Nil
case v: (h *: t) =>
val desc = summonInline[Describe[h]].describe(v.head)
desc :: describeProduct[t](v.tail, index + 1)
// Derive for any product type (case class)
inline given derived[T](using m: Mirror.ProductOf[T]): Describe[T] =
new Describe[T]:
def describe(value: T): String =
val name = value.getClass.getSimpleName
val elems = value.asInstanceOf[Product].productIterator.toList
val fields = value.asInstanceOf[Product].productElementNames.toList
val pairs = fields.zip(elems).map { (f, v) =>
s"$f=$v"
}
s"$name(${pairs.mkString(", ")})"
// Usage: derives keyword
case class Point(x: Double, y: Double) derives Describe
case class Color(r: Int, g: Int, b: Int) derives Describe
case class Pixel(position: Point, color: Color, label: String) derives Describe
// Using it manually
case class Config(host: String, port: Int, debug: Boolean)
given Describe[Config] = Describe.derived
// Extension for ergonomic usage
extension [T: Describe](value: T)
def describe: String = summon[Describe[T]].describe(value)
@main def run(): Unit =
// Primitives
println(42.describe)
println("hello".describe)
println(true.describe)
println(3.14.describe)
// Derived instances
val point = Point(1.5, 2.5)
println(point.describe)
val color = Color(255, 128, 0)
println(color.describe)
val pixel = Pixel(Point(10, 20), Color(0, 255, 0), "green")
println(pixel.describe)
val config = Config("localhost", 8080, true)
println(config.describe)
// Collections
println(List(1, 2, 3).describe)
println(Option("test").describe)
println(Option.empty[Int].describe)Use Cases
- Automatic serialization/debugging
- Reducing type class boilerplate
- Generic programming with derives
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
scalaintermediate
Given Imports and Exports
Manage given instances with Scala 3 import syntax: selective imports, exports, and priorities.
Best for: Organizing type class instances
#scala#given
scalaintermediate
Context Parameters with using/given
Use Scala 3 context parameters: given instances, using clauses, context bounds, and implicit scope.
Best for: Type class instances
#scala#given
scalabeginner
Scala Hello World Application
Create a basic Scala application with main method, string interpolation, and val/var basics.
Best for: Getting started with Scala
#scala#basics
scalabeginner
Pattern Matching Fundamentals
Use Scala pattern matching with guards, type patterns, tuple patterns, and nested extractors.
Best for: Control flow with pattern matching
#scala#pattern-matching