2

Given the following code:

import collection.JavaConversions._ def j(x: java.util.List[java.lang.Integer]): Unit = // the function body here can be any valid code println (x) val a = List(1) 

I get a type mismatch error when I call this:

j (seqAsJavaList(a)) 

Here is the error from REPL

 <console>:13: error: type mismatch; found : List[Int] required: Seq[Integer] f (seqAsJavaList(a)) ^ 

However, I can call this with no error:

 j(seqAsJavaList(List(1))) 

I'm using 2.11.2.

Can someone explain to me why seqAsJavaList behaves differently? Thanks.


Adding more context/clarification to my original question:

What I meant to ask was "why does seqAsJavaList behave differently when operating on a predefined variable a than on an in-place value List(1) when they are of the same type?" Furthermore seqAsJavaList(a) and seqAsJavaList (List(1)) return exactly the same signature java.util.List[Int]. Using the substitution model, one would expect both j (seqAsJavaList(a)) and j (seqAsJavaList (List(1)) ) to succeed. And yet, only the latter works. When both seqAsJavaList(a) and seqAsJavaList (List(1)) are java.util.List[Int], why does one usage handle Int well and the other doesn't?


Another note:

I just tried collection.JavaConverters and the result is not ideal but at least consistent:

// The definitions of j & a are the same as above. I repeat them here to save some page scrolling. // BTW, instead of f, I use j to indicate it is supposed to be a Java static method. // I mock it in Scala so that this can be easily run in REPL. def j ( ls: java.util.List [java.lang.Integer] ): Unit = println (ls) val a = List( 1 ) // new code here import collection.JavaConverters._ // Both require the explicit casting to work j ( a.map (i => i: java.lang.Integer).asJava ) j ( List(1).map (i => i: java.lang.Integer).asJava ) // These fail with the same error. j( a.asJava ) j( List(1).asJava ) // <console>:12: error: type mismatch; // found : java.util.List[Int] // required: java.util.List[Integer] // j ( List(1).asJava ) // ^ 
0

1 Answer 1

4

The problem here is not with List but with its type Int. For example this works:

scala> j ( seqAsJavaList (a.map(x => x:Integer)) ) [1] 

j expects argument type as java.util.List [java.lang.Integer]. But the return type of seqAsJavaList in your case is java.util.List [Int].

The above example works because now seqAsJavaList will take List [java.lang.Integer] and return java.util.List[java.lang.Integer]. Hence it works.

Or you could:

scala> implicit def toJavaIntegerList(ls:List[Int]):java.util.List[Integer] = seqAsJavaList(ls.map(x => x:Integer)) scala> j(List(1,2,3)) [1, 2, 3] 


To explain why this works:

j (seqAsJavaList(List(1))) 

This is equivalent to:

scala> val temp:List[Integer] = List(1) temp: List[Integer] = List(1) scala> j (seqAsJavaList(temp)) [1] 

Or better: j (seqAsJavaList(List(1:Integer)))

Type-inference is in work here. There is an implicit function

implicit def int2Integer(x:Int):java.lang.Integer 

defined in Predef. When you do j(seqAsJavaList(List(1))), type inference predicts that this can succeed legitimately by using implicit function which converts Int => java.lang.Integer. It sees that if this implicit is used with all elements of List, then call will succeed legitimately. So List(1) is actually constructed as List[Integer] rather than List[Int]

This is confirmed by checking

object Temp extends App{ import collection.JavaConversions._ def j(x: java.util.List[java.lang.Integer]): Unit = println (x) j(seqAsJavaList(List(1))) } jatinpuri@jatin:~/Desktop$ scalac -Xprint:typer Temp.scala [[syntax trees at end of typer]] // Temp.scala package <empty> { object Temp extends AnyRef with App { def <init>(): Temp.type = { Temp.super.<init>(); () }; import scala.collection.JavaConversions._; def j(x: java.util.List[Integer]): Unit = scala.this.Predef.println(x); Temp.this.j(scala.collection.JavaConversions.seqAsJavaList[Integer](immutable.this.List.apply[Integer](scala.this.Predef.int2Integer(1)))) } } 

Notice (immutable.this.List.apply[Integer](scala.this.Predef.int2Integer(1))). So List(1) is actually constructed as List[Integer] and not List[Int]

This doesn't work in original case because in doing val a = List(1), a is set as List[Int]. And the only way to change it to List[Integer] is map all contents to Integer (as there is no implicit available in scala lib that converts List[Int] => List[Integer])

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

3 Comments

First of all, thanks for taking the time. It's still a bit fuzzy to me though. Let me explain. I already figured out I had to do either seqAsJavaList (a.map (x => x: java.lang.Integer)) (as you mentioned) or seqAsJavaList (a).asInstanceOf [java.util.List [java.lang.Integer]] to get the correct type. I understand and agree with what you said: seqAsJavaList returns a java.util.List [Int] while my function f expects a java.util.List [java.lang.Integer]. Perhaps I should have been more explicit when I asked "why seqAsJavaList behaves differently". (To be continued in my next comment)
What I meant to ask was "why does seqAsJavaList behave differently when operating on a predefined variable a than on an in-place value List(1) when they are of the same type?" Furthermore seqAsJavaList(a) and seqAsJavaList (List(1)) return exactly the same signature java.util.List[Int]. Using the substitution model, one would expect both j (seqAsJavaList(a)) and j (seqAsJavaList (List(1)) ) to succeed. And yet, only the latter works. When both seqAsJavaList(a) and seqAsJavaList (List(1)) are java.util.List[Int], why does one usage handles Int well and the other doesn't?
Excellent follow-up with evidence in full display. AST certainly doesn't lie. Thank you very much. I accept this as the answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.