seadowg
seadowg

Reputation: 4265

Generically typed classes in collections in Scala

I'm having a problem with a generic class I'm creating in Scala. I have the following class:

class Channel[T, U](val endPoint : EventSource[U], val filter : Occurrence[T] => Boolean,
    val map : Occurrence[T] => Occurrence[U]) {

    def send(occurrence : Occurrence[T]) {
        if (filter(occurrence)) {
            endPoint.occur(map(occurrence))
        }
    }
}

Here a Channel[T,U] can be seen as a way of propagating an Occurrence[T] from an EventSource[T] to an EventSource[U]. The occurrence is only sent if the filter function is true and if so the occurrence is passed to map and the result of this is sent.

This class seems to compile and function correctly. My problem is that I want to attach several Channels to an EventSource[T] instance so it can propagate Occurrences to several different EventSources of different types. My confusion is basically how to do this:

class EventSource[T] {
    var List[Channel[T,U]] list = ...
}

What is U here? T is simply referenced from the type T in the EventSource that list belongs to (is a member of).

Sorry if this is a vague or confusing!

EDIT: I should have noted that I also want to be able to append to this list as in:

list = list ++ List[Channel[T, U](new Channel[T, U](endPoint, filter, map))

Is the append the real problem?

Upvotes: 4

Views: 169

Answers (2)

Neil Essy
Neil Essy

Reputation: 3607

To maintain typing you really need to use the wild card _ type. This allows you to define list in such a way where you care about the U parameter of the Channel type when adding it to the list but not when sending an occurrence to all the channels in the list. The following compiles but as it stands it is rather circular. You need a sub class of channel that does something other than send it to another EventSource.

class Occurrence[T]
class Channel[T, U](val endPoint : EventSource[U], val filter : Occurrence[T] => Boolean,
    val map : Occurrence[T] => Occurrence[U]) {
    def send(occurrence : Occurrence[T]) {
        if (filter(occurrence))
            endPoint.occur(map(occurrence))
    }
}
class EventSource[T] {
  var list: List[Channel[T,_]]  = Nil
  def addChannel[U]( endPoint : EventSource[U], filter : Occurrence[T] => Boolean, map : Occurrence[T] => Occurrence[U]) {
    list = list ++ List[Channel[T, U]](new Channel[T, U](endPoint, filter, map))
  }
  def occur( occurrence : Occurrence[T] ) {
    list foreach { _.send( occurrence ) }
  }
}

Upvotes: 1

ln2v
ln2v

Reputation: 109

If I understand your problem correctly, you could use Any:

class EventSource[T] {
  val list: List[Channel[T, Any]] = ...

EDIT: Is your code example where you use append copied? Because I noted that you're missing the types for Channel. Also, if you just want to add one element to your list you can use cons, which adds the new element at the beginning of your list:

Channel[Your, Types](your, para, meters)::list

If you for some reason absolutely want to add the new element to the end of that list, you can use :+.

Upvotes: 2

Related Questions