Scala's trait system enables flexible code composition. Type classes provide ad-hoc polymorphism. Given/using (Scala 3) and implicits (Scala 2) enable powerful context-passing patterns used throughout the ecosystem.
Traits are like Java interfaces but can contain concrete implementations. A class can extend multiple traits (no diamond problem — linearization resolves conflicts). Traits can have abstract and concrete methods, fields, and even state. Self-type annotations (this: OtherTrait =>) declare that a trait requires another trait to be mixed in, enabling dependency injection at the type level.
A type class is a trait with a type parameter: 'trait Serializable[A] { def serialize(a: A): String }'. Instances are provided as given/implicit values: 'given Serializable[Int] = new Serializable[Int] { ... }'. Functions using type classes take an implicit/using parameter: 'def print[A](a: A)(using s: Serializable[A]) = s.serialize(a)'. The compiler automatically finds and passes the right instance.
Scala 3 added extension methods as a first-class feature: 'extension (n: Int) def isEven: Boolean = n % 2 == 0'. This adds methods to existing types without subclassing. Scala 3 also replaced implicit with more explicit given/using syntax, making context passing clearer. Union types (Int | String), intersection types (A & B), and opaque type aliases are powerful new type system features.
// Type class pattern (Scala 3)
trait Show[A]:
def show(a: A): String
given Show[Int] with
def show(n: Int) = s'Int($n)'
given Show[String] with
def show(s: String) = s'"$s"'
given [A: Show] => Show[List[A]] with
def show(xs: List[A]) =
xs.map(summon[Show[A]].show).mkString('[', ', ', ']')
def display[A](a: A)(using s: Show[A]): Unit =
println(s.show(a))
display(42) // Int(42)
display(List(1, 2, 3)) // [Int(1), Int(2), Int(3)]
// Extension methods (Scala 3)
extension (s: String)
def isPalindrome: Boolean = s == s.reverse
def wordCount: Int = s.trim.split('\\s+').length
println('racecar'.isPalindrome) // true
println('Hello world foo'.wordCount) // 3
Implement a type-safe CSV encoder using type classes in Scala 3. Support: Int, Double, String, Boolean, Option[A], and case classes (using a macro or manual derivation). Write tests encoding a List[Person] to a valid CSV string.