user1315127
user1315127

Reputation:

def fn[String] seems to break Scala / java.lang.String compatibility

Hello there Stack Overflow,

I hope you'll help me with my very first question here :)

So I'm having a problem with Scala type inference. Here is the code:

object Problem {

  def ok(fn: (String) => Unit) = fn("")

  // type mismatch; found: java.lang.String("") required: String
  def fail[String](fn: (String) => Unit) = fn("")

}

What kind of String does Scala expect here?

Note that this is a minimal example to explain my problem. The original issue appeared when I tried to implement a more complex interface (Play's Iteratee, to be precise), so, no, leaving out the [String] is not an option. (If anyone thinks that the actual code would help, I'll provide it.)

I tried def fail[java.lang.String] ... but then it says expected ], found ..

I did read Scala String vs java.lang.String - type inference which gives a good explanation on java.lang.String vs. scala.Predef.String, but I still could not come up with a solution for my specific problem.

Any ideas?

EDIT: So here is the original attempt how I tried to implement http://www.playframework.org/documentation/api/2.0/scala/play/api/libs/iteratee/Iteratee.html only that I wrote String instead of T. (With T it compiles, and it makes sense!) My fail; obviously I was a bit overwhelmed by all the type parameters:

val stream = WS.url("url").get({ headers =>
  (new Iteratee[Array[Byte], String] {
    def fold[T](done: (String, Input[Array[Byte]]) => Promise[T],
                cont: (Input[Array[Byte]] => Iteratee[Array[Byte], String]) => Promise[T],
                error: (String, Input[Array[Byte]]) => Promise[T]): Promise[T] =
    {
      done("something", Input.Empty)
    }
  })
})

Regards, Hendrik

Upvotes: 3

Views: 885

Answers (2)

Submonoid
Submonoid

Reputation: 2829

This problem has nothing to do with Java vs Scala strings.

In the line def fail[String](fn: (String) => Unit) = fn("") you're definining a completely new type parameter and naming it String. This shadows the general definition.

A type paramter is needed if you intend to abstract over the type. You are not doing this in the fail example, and this should be dropped.

If you are overriding something that uses a type parameter, then you should specify this at the class level:

class A extends B[String]

Looking at the code for Iteratee, I'll guess you're trying to implement fold with its various done, cont and error functions. Fold only has one type paramter, which is used in the return type, so I'm not sure where this can come from. The input type parameters are specified on the class, so if you extend Iteratee[String, Unit] these should be provided.

Upvotes: 1

paradigmatic
paradigmatic

Reputation: 40461

When you write:

def fail[String](fn: (String) => Unit) = fn("")

The type parameter between square brackets String is just an arbitrary name that, in your case, will hide scala or java string. It is fully equivalent to:

def fail[T](fn: (T) => Unit) = fn("")

If you want to constrain the type to string, you just have to write:

def fail(fn: (String) => Unit) = fn("")

And it will work for scala and java strings (since they are the same).

Upvotes: 9

Related Questions