7

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

1 Answer 1

7

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

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

2 Comments

OK, thanks Sergey, that did the trick. Now I just have to read and understand the links you supplied. Maybe there's something there that will make me accept the ugly++ syntax with [T: ClassManifest].
I know what can make you accept that syntax, seeing what it desugars to: def foo[T : Bar] becomes def foo[T](implicit generatedName: Bar[T])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.