Skip to content
AgileLogics
6 min read

Traits

Prerequisites: Classes

A trait defines a set of methods that classes can share. Traits can have abstract methods (no body) and concrete ones.

trait Shape:
  def name: String
  def area: Double
  def describe: String = f"$name with area $area%.2f"

case class Circle(radius: Double) extends Shape:
  val name = "Circle"
  def area: Double = math.Pi * radius * radius

case class Rectangle(width: Double, height: Double) extends Shape:
  val name = "Rectangle"
  def area: Double = width * height

@main def shapes(): Unit =
  val shapes: List[Shape] = List(Circle(1), Rectangle(2, 3.5))
  shapes.foreach(s => println(s.describe))
  println(f"Total: ${shapes.map(_.area).sum}%.2f")
Circle with area 3.14
Rectangle with area 7.00
Total: 10.14
  • extends Shape makes a class implement the trait; it must define the abstract members (name, area).
  • describe is inherited as-is.
  • Code written against Shape works with every implementation — polymorphism.

Mixing in several traits

A class extends one class but can mix in many traits with with (or commas in Scala 3):

trait Greeter:
  def greet(name: String): String = s"Hello, $name"

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

class WelcomeService extends Greeter, Logger:
  def welcome(name: String): String =
    log(s"welcoming $name")
    greet(name)

@main def mixins(): Unit =
  println(WelcomeService().welcome("Ada"))
[LOG] welcoming Ada
Hello, Ada

Trait parameters and stacking

Scala 3 traits can take parameters, and traits can override each other's methods, calling super to stack behavior:

trait Formatter:
  def format(s: String): String = s

trait Trimmed extends Formatter:
  override def format(s: String): String = super.format(s.trim)

trait Upper extends Formatter:
  override def format(s: String): String = super.format(s.toUpperCase)

trait Bracketed(open: String, close: String) extends Formatter:
  override def format(s: String): String = open + super.format(s) + close

class Pretty extends Bracketed("[", "]"), Upper, Trimmed

@main def stacking(): Unit =
  println(Pretty().format("  scala  "))
[SCALA]

Calls run from the rightmost trait to the left: Trimmed, then Upper, then Bracketed. Stackable traits make it easy to compose small behaviors.