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