3

I'm working my way through Scala for the Impatient and am struggling to write tests for my solution to Chapter 10's 2nd exercise: Define a class OrderedPoint by mixing scala.math.Ordered[Point] into java.awt.Point. Use lexicographic ordering, i.e. (x, y) < (x’, y’) if x < x’ or x = x’ and y < y’.

My class does what the book asked for, but I can't seem to get it to work with SortedSet.

The class definition is like...

package sfti.ch10

import java.awt.Point

class OrderedPoint(x: Int, y: Int) extends java.awt.Point(x, y) with scala.math.Ordered[Point] {
  override def compare(that: Point): Int = {
    if (getX == that.getX) {
      getY.compare(that.getY)
    } else {
      getX.compare(that.getX)
    }
  }
}

The Spec definition is simple enough, but fails to compile once I put the SortedSet in there.

package stfi.ch10

import org.scalatest.FlatSpec
import sfti.ch10.OrderedPoint

class Ex02_OrderedPointSpec extends FlatSpec {
  "An OrderedPoint" must "make java.awt.Points comparable" in {
    val p_0_1 = new OrderedPoint(0, 1)
    val p_1_0 = new OrderedPoint(1, 0)
    val p_1_1 = new OrderedPoint(1, 1)
    val p_0_0 = new OrderedPoint(0, 0)

    assert(p_0_0.compare(p_0_0) == 0)
    assert(p_0_0.compare(p_0_1) < 0)
    assert(p_1_1.compare(p_1_0) > 0)

    // this tips over the compiler
    val sortedSet = scala.collection.SortedSet(p_1_1, p_0_0, p_1_0, p_0_1)
  }
}

Error:(19, 53) diverging implicit expansion for type sfti.ch10.OrderedPoint => Comparable[sfti.ch10.OrderedPoint] starting with method $conforms in object Predef val s = scala.collection.SortedSet[OrderedPoint](p_1_1, p_0_0, p_1_0, p_0_1)

Why won't SortedSet respect my Ordered compare?

I already looked at What is a diverging implicit expansion error? and its like they are speaking in tongues. What do I have to do to my OrderedPoint or SortedSet invocation to get the SortedSet to use the compare method from OrderedPoint?

Bob Kuhar
  • 10,838
  • 11
  • 62
  • 115

1 Answers1

2

Change it to

with scala.math.Ordered[OrderedPoint]

Ordered is invariant so the type parameter needs to match exactly.

Robin Green
  • 32,079
  • 16
  • 104
  • 187
  • That works. Seems strangely redundant, though. `class OrderedPoint(x: Int, y: Int) extends java.awt.Point(x, y) with scala.math.Ordered[OrderedPoint]`. Like I'm stuttering to tell Ordered what it is I'm working with, but I'm in the class definition, the compiler should have already known! It looks like I've got a ways to go to understand Scala's type system. – Bob Kuhar Apr 30 '18 at 03:45