简体   繁体   中英

Scala: abstract comparison method in trait

I have a trait with a size comparison function that I want to implement in a sublcass:

trait A {
    def isLessThan(that: A): Boolean
    ...
}
class SubOfA() extends A {
    ...
    override def isLessThan(that: SubOfA): Boolean = {
        this.size < that.size
    }
    ...
}

However, the method isn't a valid override because the argument type is SubOfA and not A .


I've also tried making the argument type this.type , but then when I am calling the method from an abstract setting I can't use an object of type A as the argument:

...
(foo: A, bar: A) => foo.isLessThan(bar)

This would expect type foo.type and not A which are the same but I don't think the compiler knows that yet.


Any ideas of how I could get something like this to work? I've looked all over the place to find an answer to this, but can't find anything. Maybe I don't know what is the right question to ask.

You can either use F-Bounded polymorphism (which would the solution on Java ) , or Typeclasses polymorphism (which would be the solution on Haskell ) .
My personal preference is to use typeclasses, because it is more extensible, maintainable & more typesafe - Here is more objective comparison by Rob Norris.

F-Bounded.

trait Comparable[A <: Comparable[A]] { this: A =>
  def isLessThan(that: A): Boolean
}

class SubOfComparable extends Comparable[SubOfComparable] {
  val size: Int = ???
  override final def isLessThan(that: SubOfComparable): Boolean =
    this.size < that.size
}

Typeclasses.

trait Comparator[T] {
  def isLessThan(a: T, b: T): Boolean
}

object syntax {
  object comparator {
    implicit final class ComparatorOps[T](val self: T) extends AnyVal {
      final def < (that: T)(implicit C: Comparator[T]): Boolean =
        C.isLessThan(self, that)
    }
  }
}

class Sub {
  final val size: Int = ???
}

object Sub {
  implicit val SubComparator: Comparator[Sub] = new Comparator[Sub] {
    override final def isLessThan(a: Sub, b: Sub): Boolean =
      a.size < b.size
  }
}

import syntax.comparator._
val a = new Sub(...)
val b = new Sub(...)
a < b

You can fix the first method with:

class SubOfA() extends A {

    override def isLessThan(that: A): Boolean = that match {
        case that : subOfA =>  this.size < that.size
        case _ => throw new UnsupportedOperationException("Wrong comparison") //or whatever behaviour deemed suitabe here
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM