Traits
Prerequisites: Inheritance and interfaces
A trait is a reusable piece of behavior — methods and state — that you can mix into any class. Think of it as an interface that can carry an implementation and fields.
trait Greeter {
String greet() { "Hello, I'm ${name}" }
abstract String getName()
}
trait Timestamped {
List<String> history = []
void log(String event) { history << "${history.size() + 1}: $event" }
}
class Robot implements Greeter, Timestamped {
String name
}
def r = new Robot(name: 'R2')
println r.greet()
r.log('powered on')
r.log('beeped')
println r.history
println r instanceof Greeter
Hello, I'm R2
[1: powered on, 2: beeped]
true
- A class
implementstraits just like interfaces — as many as it wants. - Traits can declare state (
history) — each object gets its own. - An
abstractmethod lets a trait require something from the class.
Conflicts
trait Walker { String move() { 'walking' } }
trait Swimmer { String move() { 'swimming' } }
class Duck implements Walker, Swimmer {}
class Penguin implements Swimmer, Walker {
String move() { "${Swimmer.super.move()} and ${Walker.super.move()}" }
}
println new Duck().move()
println new Penguin().move()
swimming
swimming and walking
When two traits define the same method, the last one declared wins
(Swimmer for Duck). To combine them, override the method and call
TraitName.super.method() explicitly.
Adding traits at runtime
trait Loud {
abstract String getText()
String shout() { text.toUpperCase() + '!' }
}
class Message {
String text
}
def msg = new Message(text: 'deploy done')
def loud = msg.withTraits(Loud)
println loud.shout()
println loud instanceof Loud
println msg instanceof Loud
DEPLOY DONE!
true
false
withTraits returns a new proxy object that has the extra behavior and
forwards everything else (like getText()) to the original; msg itself
is unchanged.
Traits vs. inheritance
| Use | When |
|---|---|
Inheritance (extends) |
A true "is-a" relationship with one parent |
| Interface | A contract with no shared implementation |
| Trait | Shared, reusable behavior across unrelated classes |
Traits are compiled to interfaces plus helper classes, so they work with Java code that expects the interface.