user3390929
user3390929

Reputation: 68

Scala: Problems creating generic collection

I have two sorted lists, and want to create an iterator which will merge the two lists in sorted oder. I'm new to Scala and especially new with writing generic classes. I get a compile error that I'm unable to figure out.

Here is the code for MergingIterator

class MergingIterator[ElementType <: Ordered[ElementType]] (iterator1: BufferedIterator[ElementType], iterator2: BufferedIterator[ElementType]) extends Iterator[ElementType]{


 override def hasNext: Boolean = {
   iterator1.hasNext || iterator2.hasNext
 }

 override def next(): ElementType = {
   if(!iterator1.hasNext && !iterator2.hasNext){
    throw new IllegalStateException("All iterators empty.  No next element")
   }
   val e1 : Option[ElementType] = if(iterator1.hasNext) Some(iterator1.head) else None
   val e2 : Option[ElementType] = if(iterator2.hasNext) Some(iterator2.head) else None
   if(e1.isDefined && e2.isDefined){
     val e1a = e1.get
     val e2a = e2.get
     if(e1a.equals(e2a) || e1a < e2a){
       iterator1.next()
     }
     else {
       iterator2.next()
     }
   }
   else if (e1.isDefined){
     iterator1.next
   }
   else if (e2.isDefined){
     iterator2.next()
   }
   else{
     throw new Exception("InvalidState.  No elements present")
   }
 }
}

And here is the Unit Test, which is what doesn't compile:

class MergingIteratorTest extends AnyFunSuite {

  test("Both Iterators Empty"){
    runTest(List(), List(), List())
  }

  private def runTest(vals1 : List[ComparableInt], vals2: List[ComparableInt], expected: List[ComparableInt]): Unit ={
    val it1 = vals1.iterator.buffered
    val it2 = vals2.iterator.buffered
    val merging = new MergingIterator[ComparableInt](it1, it2)
    val merged = merging.toList
    assert(expected.equals(merged))
  }

  case class ComparableInt(value: Int) extends Ordered[Int] {
    override def compare(that: Int): Int = value - that
  }

}

However when I try to compile, I get the following errors.

Error:(14, 9) type arguments [MergingIteratorTest.this.ComparableInt] do not conform to class MergingIterator's type parameter bounds [ElementType <: Ordered[ElementType]]
    val merging = new MergingIterator[ComparableInt](it1, it2)
Error:(14, 23) type arguments [MergingIteratorTest.this.ComparableInt] do not conform to class MergingIterator's type parameter bounds [ElementType <: Ordered[ElementType]]
    val merging = new MergingIterator[ComparableInt](it1, it2)

I'm sure it's something stupid that I'm doing wrong, but due to my lack of experience with scala I've been able to figure out what the problem is. Any help here would be appreciated.

Upvotes: 0

Views: 58

Answers (2)

jwvh
jwvh

Reputation: 51271

Same thing with the Ordering type class.

class MergedIterator[ElmTyp:Ordering](itrA: Iterator[ElmTyp]
                                     ,itrB: Iterator[ElmTyp]
                                     ) extends Iterator[ElmTyp] {
  import Ordering.Implicits._
  private val itr1 = itrA.buffered
  private val itr2 = itrB.buffered

  override def hasNext: Boolean = itr1.hasNext || itr2.hasNext
  override def next(): ElmTyp =
    if      (!itr1.hasNext)         itr2.next()
    else if (!itr2.hasNext)         itr1.next()
    else if (itr1.head > itr2.head) itr2.next()
    else                            itr1.next()
}

Upvotes: 1

Ivan Kurchenko
Ivan Kurchenko

Reputation: 4063

You need to make

case class ComparableInt(value: Int) extends Ordered[ComparableInt] {
    override def compare(that: ComparableInt): Int = value.value - value.value
}

The issue is in [ElementType <: Ordered[ElementType]] type bounds - you see ElementType should be ordered to itself and your case ComparableInt implements Ordered[Int] and meaning ComparableInt is not Ordered to itself as MergingIterator signature expects.

Upvotes: 1

Related Questions