Kevin Li
Kevin Li

Reputation: 1538

Type-checking collections with elements with different traits

Is there any way I can enforce a method returning something along the lines of (in regex notation):

(T with A) (T with A with B)+ (T with B)

If I return Traversable[T], it drops the bound traits. Likewise, I can't return Traversable[T with A with B], because this would be inaccurate for the first and last elements.

I'm not sure how to get around this. It introduces some implicit conditions into my program, and I feel like I'm abusing the type system by using .asInstanceOf[] casts. Maybe I'm using the wrong kind of data structure?

Here's a sample of the code I'm writing, for an example of what I mean. I'm looking to enforce the route method. The User class extends type T, I've left out the code because there's a lot.

trait Producer extends User {
  def send(file: Data)
}

trait Consumer extends User {
  def receive(file: Data)
}

...

def route(sender: T with Producer, receiver: T with Consumer): Traversable[T]

def transfer(sender: T with Producer, receiver: T with Consumer, file: Data) {
  val path = route(sender, receiver)
  if (!path.isEmpty) {
    sender send file

    val nextHop = route(sender, receiver).tail.head

    nextHop.asInstanceOf[T with Consumer] receive file

    if (nextHop != receiver) {
      transfer(nextHop.asInstanceOf[T with Producer], receiver, file)
    }
  }
}

Upvotes: 1

Views: 113

Answers (1)

dhg
dhg

Reputation: 52701

You should definitely avoid casts with .asInstanceOf[].

Scala can easily return multiple values from a method using a Tuple, so why not return a 3-tuple of type (T with A, Traversable[T with A with B], T with B)?

Here's an example:

trait A
trait B
class T

def f(): (T with A, Traversable[T with A with B], T with B) = {
  (new T with A, List(new T with A with B), new T with B)
}

val (a, abs, b) = f()

Upvotes: 3

Related Questions