Reputation: 93
I have been going through the Programming Scala book(by Martin Odersky,Lex Spoon,Bill Venners ed1) and came across traits. A section that I find interesting is stackable modifications. The example used is
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
trait Incrementing extends IntQueue {
abstract override def put(x: Int) {super.put(x+1)}
}
trait Filtering extends IntQueue{
abstract override def put(x: Int){
if(x >=0) super.put(x)
}
}
so the example provided has a concrete class "BasicIntQueue that extends IntQueue as follows
import scala.collection.mutable.ArrayBuffer
class BasicIntQueue extends IntQueue{
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) {buf +=x}
}
scala> val queue = (new BasicIntQueue with Incrementing with Filtering)
scala> queue.put(-1);queue.put(0);queue.put(1)
scala> queue.get() = 1
So the example shows that both the filtering and incrementing are "chained" and executed before the elements are "put" into the queue.
I was just wondering how this could be accomplished in Groovy. Maybe it is not needed because of Groovy's meta-programability.
Upvotes: 3
Views: 665
Reputation: 15668
Beginning from Groovy 2.3 Groovy supports traits and also stackable traits. The implementation looks therefore exactly as in Scala:
interface IntQueue {
Integer get()
void put(Integer x)
}
trait Incrementing implements IntQueue {
void put(Integer x) { super.put(x+1) }
}
trait Filtering implements IntQueue {
void put(Integer x) { if(x >= 0) super.put(x) }
}
class BasicIntQueue implements IntQueue {
private buf = new ArrayList<Integer>()
Integer get() { buf.remove(0) }
void put(Integer x) { buf << x}
String toString() { buf.toString() }
}
def queue = new BasicIntQueue().withTraits Incrementing, Filtering
queue.put(-1)
queue.put(0)
queue.put(1)
assert queue.get() == 1
Upvotes: 3
Reputation: 66069
Groovy doesn't have a natural way to do stackable traits. Categories provide some of the trait functionality, but they're not well suited to overriding methods and can't be stacked without much metaclass magic.
A better approach in groovy would be to apply the decorator pattern along with the @Delegate
annotation. Each "trait" can override the appropriate behavior and delegate to the "super" class. Example:
interface IntQueue {
def get()
def put(x)
}
class Incrementing implements IntQueue {
@Delegate IntQueue self
def put(x) {
self.put(x+1)
}
}
class Filtering implements IntQueue {
@Delegate IntQueue self
def put(x) {
if (x >= 0) {
self.put(x)
}
}
}
class BasicIntQueue implements IntQueue {
private buf = []
def get() { buf.pop() }
def put(x) { buf << x }
}
You could then construct an object with the desired traits like so:
def q = new Filtering(self: new Incrementing(self: new BasicIntQueue()))
Upvotes: 2