5

I have an object with a bunch of related routines and all their declarations look the same, something like

object Sorting {
  def qsort[a <% Ordered[a]] ....

  def partition[a <% Ordered[a]] ...

  def qselect[a <% Ordered[a]] ...
}

Is there a way to specify the type constraint in one place and reduce declarations to something like qsort[a](xs: Stream[a]) or even better just qsort(xs: Stream[a]) ?

For the time being I've decided to roll with implicit classes

object Implicits {
  implicit class SortableArray[a <% Ordered[a]](xs: Array[a]) {
    def qsort = {...}
  }
}

object Application {
  import Implicits._
  def main(args: Array[String]) = {
    val xs = Array(1,2,3)
    xs.qsort
  }
}
synapse
  • 5,588
  • 6
  • 35
  • 65

2 Answers2

3

Unfortunately you can not declare type as type U[T] = T <% Ordered[T]. This will not work and even will not compile.

But, there are some workarounds you can apply to your code

Confider this think-flow:

As described here:

def f[A <% B](a: A) = a.bMethod

is the same as

def f[A](a: A)(implicit ev: A => B) = a.bMethod

and this

def g[A : B](a: A) = h(a)

is the same as

def g[A](a: A)(implicit ev: B[A]) = h(a) .

So going back to you example:

def qsort[A <% Ordered[A]] = ???

... is translated to:

def qsort[A](implicit ev: A => Ordered[A]) = ???

... now you can introduce type parameter like:

type O[A] = A => Ordered[A]

... and use it as:

def gsort[A] (implicit ev: O[A])

... which can be simplified into:

def gsortX[A : O]

Then all your code you can write as:

Before

object Sorting {

  def qsort[A <% Ordered[A]] = ???

  def partition[A <% Ordered[A]] = ???

  def qselect[A <% Ordered[A]] = ???
}

After

object Sorting {

  type O[A] = A => Ordered[A]

  def qsort[A: O] = ???

  def partition[A: O] = ???

  def qselect[A: O] = ???
}

Or even better using trait

trait Sorting[A] {
  type O = A => Ordered[A]
  implicit def f : O

  def qsort = ???

  def partition = ???

  def qselect = ???
}

I hope this helps somehow :)

Community
  • 1
  • 1
pawel.panasewicz
  • 1,831
  • 16
  • 27
  • It seems to work fine with object but how should I use the trait? Extending some object with `object IntSorting extends Sorting[Int]` kinda defeats the purpose. – synapse Oct 09 '13 at 10:05
  • @Synapse, You can use pimp my library approach as well, but then you must create implicit wrapper with similar method as in trait: `implicit def toPimp[A](xs: Stream[A]) = new { def qsort[A](xs:Stream[A]) = new Sorting[A](xs: Stream[A]) {...}.sort(xs)}` and then you can use it `xs.sort`. – pawel.panasewicz Oct 09 '13 at 11:49
  • He could also use `Ordering` instead of `Ordered`, which would obviate the need for the view bound. – DaoWen Oct 11 '13 at 00:01
1

Not with an alias, as answered in this question. That view bound actually adds an implicit parameter to each of those methods, which isn't easily abstracted into a type alias.

Community
  • 1
  • 1