I am trying to realize a simple project goal, but the complexity of a system like Scala gives me some headache. After comparing Traversable, Iterator, Iterable, Stream, View, etc. My solution is to define a custom attribute (just call it Stream for short), which
- is nonequivalent (my stream semantically only makes sense like some
Stream[StreamEntry] , and I want to avoid meaningless types like Stream[Int] ) - has a similar use for
Iterable - all members, such as
take , drop , etc., should return a Stream , not the underlying Iterable .
This is what I have tried so far:
Approach 1
To outline a usage example, a simple example (which violates the third design goal):
case class StreamEntry(data: Double)
Approach 2
This third requirement requires the use of a template tag instead of a base tag (I hope this is the standard terminology for referring to SomeCollection or SomeCollectionLike). This means that I have to use IterableLike[StreamEntry, Stream] , which overrides the return types of the representing collection in the same way as Iterable extends IterableLike[A, Iterable[A]] to return Iterable s. My idea was to do almost the same thing as Iterable . This will:
// this is exactly the way `Iterable` is defined, but non-generic trait Stream extends Traversable[StreamEntry] with GenIterable[StreamEntry] with GenericTraversableTemplate[StreamEntry, Stream] with IterableLike[StreamEntry, Stream] { ... }
Unfortunately, this does not compile, because Stream appears as a GenericTraversableTemplate argument to GenericTraversableTemplate , and now the compiler requires a template argument (exactly one) for Stream , which makes sense.
Approach 3, 4, ...
From this point on, I got lost in the type system. Just removing with GenericTraversableTemplate results in an incompatible newBuilder type and inappropriate inheritance due to conflicts in the type parameters in the GenericTraversableTemplate of GenInterable and Traversable .
Perhaps the closest solution was the following:
trait Stream extends TraversableLike[StreamEntry, Stream] with IterableLike[StreamEntry, Stream] { val metaInfo: String def seq = this def newBuilder: scala.collection.mutable.Builder[StreamEntry, Stream] = ??? }
This compiles, but unfortunately I have no idea how to implement Builder. Can I reuse generic builder for my non-generic trait? In fact, although I can do without Builder, because I never want to create a new Stream from other collections. But at the present time I am experiencing some strange behavior while working with this approach, which I cannot fully understand. For example:
val s = new Stream { val metaInfo = "something" val iterator = StreamEntry(1) :: StreamEntry(2) :: StreamEntry(3) :: Nil toIterator } // executing the following independently (not in sequence) results in: s.take(1) // throws: scala.NotImplementedError: an implementation is missing // seems to require a Builder :( s.toArray // works s.toIterator // works s.toIterable // throws: java.lang.ClassCastException: cannot be cast to scala.collection.Iterable
Now I feel a little lost deep in a system like Scala. Am I still on the right track with this latest approach and is Builder just the missing piece in this puzzle?
And what would the Builder implementation look like for a nonequivalent type without caching? The direct idea to implement += would be to use some mutable Buffer, but that would be very strong against using Iterators in the first place ... And how do I implement the to element if I don't know how to build a class of this type? I assume that all the relevant code should be somewhere in the library, I just canβt dig it out.