Traits are Scala's tool for abstraction, code reuse and modular design.
A trait declares abstract members (methods, values, types) and can also provide concrete implementations. Classes and objects extend one class and any number of traits: class Duck extends Animal, Swimmer, Flyer (Scala 3 syntax; with also works).
Use traits to:
- define interfaces (
trait Repository[A] { def find(id: Long): Option[A] }), - share behaviour (a
Loggingtrait with a concretelogmethod), - stack modifications (several traits overriding the same method and calling
super).
When multiple traits define the same method, Scala uses linearization: the class and its traits are put in a single order (roughly right to left) and super calls the next one in that order. This gives predictable stackable behaviour, unlike the diamond problem in some languages.
Scala 3 traits can take parameters (trait Greeting(val name: String)), which only the class that first mixes it in passes.
Use an abstract class instead when you need Java interoperability with constructors or when a type is clearly a base implementation. Otherwise prefer traits.
Mark a trait sealed when all implementations live in the same file: then the compiler knows every subtype, enabling exhaustive pattern matching (next lesson).
Example
trait Shape:
def area: Double // abstract
def describe: String = f"${getClass.getSimpleName} with area $area%.2f"
trait Logged extends Shape:
override def describe: String = "[log] " + super.describe
trait Loud extends Shape:
override def describe: String = super.describe.toUpperCase
class Circle(r: Double) extends Shape:
def area = math.Pi * r * r
class Square(s: Double) extends Shape, Loud, Logged:
def area = s * s
trait Greeting(val greeting: String):
def greet(n: String) = s"$greeting, $n"
object Formal extends Greeting("Good day")
@main def traitsDemo(): Unit =
println(Circle(1).describe) // Circle with area 3.14
println(Square(2).describe) // [log] SQUARE WITH AREA 4.00
println(Formal.greet("Ana")) // Good day, AnaRemember
- Traits mix abstract and concrete members; a class can extend many
- Linearization orders traits;
supercalls the next in line - Scala 3 traits can take parameters
sealedtraits enable exhaustive matching
Watch out for
- Assuming trait order doesn't matter:
extends A, Bandextends B, Acan behave differently.