A possible solution is the following:
class Pair[ T <% Comparable[T] ](r:T,t:T) {
def sizeRelationship = r.compareTo(t)
}
Note the viewable-as <% in place of the subtype-of <:
sealed class Person(val importance:Int) {
def compareTo(o: Person): Int = ???
}
class Student extends Person(10)
class Teacher extends Person(50)
implicit class PersonComparable[T <: Person](x: T) extends Comparable[T] {
def compareTo(o: T): Int = x.compareTo(o)
}
val mixed: Pair[Person] = new Pair(new Student,new Teacher) /* compiles */
val notMixed = new Pair[Student](new Student, new Student) /* compiles */
The main difference with the original code is that in place of inheriting (implementing) the Comparable trait, the domain classes are retrofitted with it, by means of an implicit class. This makes it possible to exhibit the polymorphic behavior that is required by the type signature of:
val notMixed = new Pair[Student](...)
The main practical advantage versus the solution of using the base type signature in the Pair instance:
val notMixed = new Pair[Person](...)
is more accurate typing of the Pair instances, which in turn can enable more sophisticated processing downstream (e.g. pattern matching, etc).