javazquez
javazquez

Reputation: 93

Groovy equivalent to Scala trait stackable modifications?

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

Answers (2)

ChrLipp
ChrLipp

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

ataylor
ataylor

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

Related Questions