scalaintermediate

Traits and Mixin Composition

Compose behavior with Scala traits: stackable modifications, self-types, and diamond resolution.

scala
// Basic traits
trait Greeting:
  def greet(name: String): String

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

trait Timestamped:
  def timestamp: Long = System.currentTimeMillis()

// Mixin composition
class ConsoleGreeter extends Greeting with Logger with Timestamped:
  def greet(name: String): String =
    val msg = s"Hello, $name! (at $timestamp)"
    log(msg)
    msg

// Stackable trait pattern
trait StringTransformer:
  def transform(s: String): String

trait Uppercasing extends StringTransformer:
  abstract override def transform(s: String): String =
    super.transform(s.toUpperCase)

trait Trimming extends StringTransformer:
  abstract override def transform(s: String): String =
    super.transform(s.trim)

trait Slugifying extends StringTransformer:
  abstract override def transform(s: String): String =
    super.transform(s.replaceAll("\\s+", "-"))

class BaseTransformer extends StringTransformer:
  def transform(s: String): String = s

// Self-type: require another trait
trait Repository:
  def save(data: String): Unit

trait DatabaseConfig:
  def connectionUrl: String

trait JdbcRepository extends Repository:
  self: DatabaseConfig =>  // requires DatabaseConfig
  def save(data: String): Unit =
    println(s"Saving '$data' to $connectionUrl")

class ProductionRepo extends JdbcRepository with DatabaseConfig:
  def connectionUrl: String = "jdbc:postgresql://localhost:5432/prod"

@main def run(): Unit =
  val greeter = ConsoleGreeter()
  println(greeter.greet("Alice"))

  // Stackable transformations
  val pipeline = new BaseTransformer
    with Trimming
    with Slugifying
    with Uppercasing

  println(pipeline.transform("  Hello World  "))  // HELLO-WORLD

  // Order matters!
  val pipeline2 = new BaseTransformer
    with Uppercasing
    with Slugifying
    with Trimming

  println(pipeline2.transform("  Hello World  "))

  // Self-type usage
  val repo = ProductionRepo()
  repo.save("product-123")

Use Cases

  • Composable behavior via mixins
  • Stackable modification pattern
  • Dependency declaration with self-types

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.