Generic type parameters for conversion to parallel dialing

I have this function to convert Array to ParArray by specifying the number of threads as a parameter:

 def parN[T](collection: Array[T], n: Int) = { val parCollection = collection.par parCollection.tasksupport = new ForkJoinTaskSupport( new concurrent.forkjoin.ForkJoinPool(n)) parCollection } 

Now I would like to do this general so that it works with collections other than Array :

 def parN[S, T[S] <: Parallelizable[S, ParIterable[S]]](collection: T[S], n: Int) = { val parCollection = collection.par parCollection.tasksupport = new ForkJoinTaskSupport( new concurrent.forkjoin.ForkJoinPool(n)) parCollection } 

But when I call it with parN(Array(1, 2, 3), 2) , I get this error:

 inferred type arguments [Int,Array] do not conform to method parN type parameter bounds [S,T[S] <: scala.collection.Parallelizable[S,scala.collection.parallel.ParIterable[S]]] 

On the other hand, this works:

 val x: Parallelizable[Int, ParIterable[Int]] = Array(1, 2, 3) 

Any ideas what could be wrong with my type parameters?

+7
source share
1 answer

First of all, note that this is a problem specific to Array : your method works for List or any other regular collection (except for those that have several type parameters or not). Example:

 scala> parN(List(1,2,3), 2) res17: scala.collection.parallel.ParIterable[Int] = ParVector(1, 2, 3) scala> parN(Set(1,2,3), 2) res18: scala.collection.parallel.ParIterable[Int] = ParSet(1, 2, 3) 

Array always a special case when it comes to collections, because ... it's not a collection. Because of Java, its definition is final class Array[T] extends Serializable with Cloneable . However, there are two options available everywhere that can convert Array to collection type ( ArrayOps and WrappedArray ). And these types implement Parallelizable , so everything should be fine ... except that type inference is in the way:

The type parameter is only defined as T[S] , so when it receives Array[Int] it gladly displays Array[Int] , and then checks the boundaries: failure, Array not distributed Parallelizable . Game over.

I see two options:

  • You can explicitly say you want Parallelizable :

     def parN[S](collection: Parallelizable[S, ParIterable[S]], n: Int) 

    Or, if you need access to the actual type T (in your case not, but who knows):

     def parN[S, T[S] <: Parallelizable[S, ParIterable[S]]](collection: T[S] with Parallelizable[S, ParIterable[S]], n: Int) 
  • or you can accept anything that can be implicitly converted to Parallelizable using an implicit parameter:

     def parN[S, T <% Parallelizable[S, ParIterable[S]]](collection: T, n: Int) 

    which is a short version:

     def parN[S, T](collection: T, n: Int)(implicit ev: T => Parallelizable[S, ParIterable[S]]) 

All of them should work. In your case, I would recommend the very first: this is the most readable one that does the job.

+5
source

All Articles