3

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

2 Answers 2

9

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).

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

4 Comments

Thanks, quite obvious now that you say it... :|
This answer is correct, I chose @submonoid's though for working with my method's signature which I cannot actually change.
@Hendrik - The signature doesn't make sense as far as I can tell. Why can't you change it? What must the signature be? (Could you be mistaken about what it has to be?)
Added the original code above, should explain my misconception.
1

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.

3 Comments

Yes, I get it now - argh! Dispatching on the type is an interesting approach. Thanks!
That's a very good point, I shall remove that. Sorry, wrote my answer too quickly.
Too bad, looked interesting ;(

Your Answer

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