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
  }
}

2 Answers 2

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 :)

Sign up to request clarification or add additional context in comments.

3 Comments

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, 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.
He could also use Ordering instead of Ordered, which would obviate the need for the view bound.
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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.