पाठ 8 / 25
Traits and Mixin Composition
Use traits for interfaces and reusable behaviour, and understand linearisation.
Traits: interfaces with superpowers
A trait defines abstract and concrete members and can be mixed into classes: class Invoice extends Document with Printable with Auditable. A class extends one class but can mix in many traits, so traits are Scala's tool for sharing behaviour across unrelated types, like Java interfaces with default methods but more powerful. In Scala 3, traits can also take parameters (trait Greeting(val prefix: String)). When several traits override the same method and call super, Scala uses linearisation: traits are stacked from right to left, so the rightmost trait runs first and its super call reaches the next one. This enables the stackable modifications pattern (logging, validation and caching layers). A sealed trait or class can only be extended in the same file, so the compiler knows all subtypes and can check pattern matches for exhaustiveness. Self types (self: Logger =>) declare that a trait requires another trait to be mixed in. Prefer small, focused traits and composition over deep class hierarchies.
Stackable traits
Each layer calls super, and the order of mixing determines the order of execution.
trait PaymentGateway:
def charge(orderId: String, amountPaise: Long): String
class SimpleGateway extends PaymentGateway:
def charge(orderId: String, amountPaise: Long): String =
s"pay_${orderId}_$amountPaise"
trait Logging extends PaymentGateway:
abstract override def charge(orderId: String, amountPaise: Long): String =
println(s"charging $orderId for $amountPaise paise")
super.charge(orderId, amountPaise)
trait Validating extends PaymentGateway:
abstract override def charge(orderId: String, amountPaise: Long): String =
require(amountPaise > 0, "amount must be positive")
super.charge(orderId, amountPaise)
// rightmost trait runs first: Validating, then Logging, then the real gateway
val gateway = new SimpleGateway with Logging with Validating
println(gateway.charge("o-1", 49900))
trait Greeting(val prefix: String): // Scala 3 trait parameters
def greet(name: String) = s"$prefix, $name"
class FormalGreeter extends Greeting("Good morning")
println(FormalGreeter().greet("Asha"))Layers of a sandwich
Mixing traits is like stacking sandwich layers. The order you stack them decides what you bite into first, and each layer passes the bite on to the one beneath it with super.
त्वरित जाँच: With `new Gateway with Logging with Validating`, which trait's charge runs first?
- Logging
- Gateway
- They run in parallel
- Validating
Answer
Validating — Linearisation puts the rightmost trait first; its super call reaches Logging, then the class.