lasaro
lasaro

Reputation: 504

Subtyping function parameters in Scala

I am trying to define an abstract class that has operators to compare two instances of the class. When concretizing the class, however, I want the methods to only compare instances of the same type. Something like this

abstract class ComparableSuper{
  def <(other: ComparableSuper): Boolean  
  def <=(other: ComparableSuper): Boolean  
  def >(other: ComparableSuper): Boolean
  def >=(other: ComparableSuper): Boolean
}


class Comparable (val a: Int) extends ComparableSuper {
   def <(other: Comparable): Boolean = this.a < other.a
   def >(other: Comparable): Boolean = this.a > other.a
   def <=(other: Comparable): Boolean = this.a <= other.a
   def >=(other: Comparable): Boolean = this.a >= other.a
}

Of course this code does not compile because I am not overriding the methods in the abstract class. If I change Comparable to ComparableSuper in the methods, however, I won't have the assurance that the field a is there.

Is there a way I could specify the type of the class in the method signature?

Thanks in advance.

Upvotes: 1

Views: 194

Answers (2)

Travis Brown
Travis Brown

Reputation: 139058

In this case using math.Ordered or math.Ordering is a better idea, but if you do need this pattern, you can use F-bounded polymorphism:

trait Foo[A <: Foo[A]] {
  def f(that: A): Int
}

class Bar(val x: Int) extends Foo[Bar] {
  def f(that: Bar) = this.x - that.x
}

There's a bit of syntactic overhead involved in parametrizing the supertype, but it allows you to have methods that require an instance of the same subclass.

Upvotes: 2

tenshi
tenshi

Reputation: 26586

I highly recommend you to look at Ordering type class.

I find, that type-class approach to this problem is much better than Comaprable way of doing it (where objects, that you want to compare, actually extend Comparable).

With type-class approach you will also give you more type-safety and flexibility. You can actually define Ordering instances for existing classes (classes that you can't control and change).


Ordering can be a little bit clumsy to use, but Ordered has implicits that will allow you to write code like this:

import math.Ordered._

def isGreater[T : Ordering](a: T, b: T) = a > b

So you even don't compromise convenience. (by the way, Ordered is equivalent to Java's Comparable)

Upvotes: 3

Related Questions