Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Array map returns ArraySeq

Tags:

scala

Why can't I have type parameters in my factory methods below?

import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.FunSuite

@RunWith(classOf[JUnitRunner])
class WhyScalaNeverWillMakeIt extends FunSuite {

  test("Array becomes ArraySeq when you least want it") {
    val arr = Array("A", "B", "C")
    def f: String => Dummy = new Dummy(_)

    val bucket = new Bucket[Dummy](arr.map(f))
//    val bucket2 = Bucket[String, Dummy](arr, f)
//    val bucket3 = Bucket[Dummy](arr, f)
    val bucket4 = Bucket(arr, f)
  }

  class Bucket[T]( val arr: Array[T] )  {/* Loads of business logic */}

  object Bucket {
//    def apply[T, U](arr: Array[T], f:T=>U):Bucket[U] = new Bucket[U](arr.map( b => f(b) ))
//    def apply[T](arr: Array[String], f:String=>T):Bucket[T] = new Bucket[T](arr.map( b => f(b) ))
    def apply(arr: Array[String], f:String=>Dummy):Bucket[Dummy] = new Bucket[Dummy](arr.map(f))
  }


  class Dummy(val name: String)
}

If I uncomment the factory methods in object Bucket I get:

error: type mismatch;
found   : scala.collection.mutable.ArraySeq[T]
required: Array[T]
def apply[T](arr: Array[String], f:String=>T):Bucket[T] = new Bucket[T](arr.map( b => f(b) ))

Somehow the Scala compiler got confused (or is it me? ;-) ) when I introduced the type parameter T. Maybe I'm doing something very wrong here, but I can't see why introducing a type parameter means that the map function should change return type from Array[T] to ArraySeq[T].

I know that Array is just a wrapper around Java Array and that I probably should use one of the more fancy Scala classes, such as Seq or List, but that still doesn't explain this rather odd behaviour.

Can someone explain why this is happening and maybe also how to fix it (still using Arrays)?

Edit: I'm using scala 2.9.1

like image 893
Jorgen Avatar asked Oct 11 '12 10:10

Jorgen


1 Answers

Just add ClassManifest context bound:

    def apply[T, U: ClassManifest](arr: Array[T], f: T => U): Bucket[U] = new Bucket[U](arr.map(b => f(b)))
    def apply[T: ClassManifest](arr: Array[String], f: String => T): Bucket[T] = new Bucket[T](arr.map(b => f(b)))

For details check this and this

like image 124
Sergey Passichenko Avatar answered Nov 13 '22 20:11

Sergey Passichenko