Traits & Mixins

Linearization: traits are applied right to left; super refers to the next trait in the linearized order.

13.1 Traits — interfaces with implementation

trait Greeter:
  def name: String                          // abstract
  def greet(): String = s"Hello from $name" // concrete

trait Logger:
  def log(msg: String): Unit = println(s"[LOG] $msg")

class Service(val name: String) extends Greeter, Logger    // Scala 3 (Scala 2: with)

13.2 Trait parameters (Scala 3)

trait Named(val label: String)
class Item extends Named("item")

13.3 Stackable modifications & linearization

Linearization: traits are applied right to left; super refers to the next trait in the linearized order.

abstract class IntQueue:
  def put(x: Int): Unit
  def get(): Int

class BasicQueue extends IntQueue:
  private val buf = scala.collection.mutable.ArrayBuffer.empty[Int]
  def put(x: Int) = buf += x
  def get() = buf.remove(0)

trait Doubling extends IntQueue:
  abstract override def put(x: Int) = super.put(2 * x)

trait Incrementing extends IntQueue:
  abstract override def put(x: Int) = super.put(x + 1)

val q = new BasicQueue with Incrementing with Doubling
q.put(10)
q.get()     // 21 — Doubling runs first (rightmost), then Incrementing

13.4 Self types

trait UserRepo:
  def find(id: Int): String

trait UserService:
  this: UserRepo =>                 // requires a UserRepo to be mixed in
  def describe(id: Int) = s"User: ${find(id)}"

13.5 Transparent & sealed traits

sealed trait Shape            // all subtypes in this file → exhaustive matching
transparent trait Kind        // not inferred as a type (Scala 3)

13.6 Universal traits & mixin composition patterns

The "cake pattern" (self types for DI) was popular in Scala 2; today prefer constructor injection, givens, or ZIO layers.