10
votes

I have the following code in Java:

public class JavaClass {

    public static void method( Object x ) {
    }

    public static void varargsMethod( Object... x ) {
    }

}

When I try and access it from Scala,

object FooUser {
  JavaClass.method(true)
  JavaClass.varargsMethod(true) // <-- compile error
}

I get the following compile error:

type mismatch; found : Boolean(true) required: java.lang.Object Note: primitive types are not implicitly converted to AnyRef. You can safely force boxing by casting x.asInstanceOf[AnyRef]

The error message is very helpful and shows how to fix the error, but I was wondering why the compiler is (apparently) happy to implicitly convert a scala.Boolean in one method call but not the other. Is this a bug or intentional?

Updated to add: I'm using Scala 2.8. If I make the varargsMethod signature

public static <T> void varargsMethod(T... xs) {

instead, then the error also goes away. I'm still puzzled as to why the compiler can't figure it out.

4
THANK YOU! This trick <T> void varargsMethod(T... xs) works!!!ZiglioUK

4 Answers

5
votes

Scala varargs and Java varargs are different. You need to do a conversion:

def g(x: Any*) = x.asInstanceOf[scala.runtime.BoxedObjectArray]
.unbox(x.getClass)
.asInstanceOf[Array[Object]]  
...
JavaClass.varargsMethod(g(true))

or (in 2.8.0+)

JavaClass.varargsMethod(java.util.Arrays.asList(true))
2
votes

Since scala.Boolean is a subclass of scala.AnyVal but not scala.AnyRef (translated to java.lang.Object), a Boolean cannot be passed to a method expecting Object(s).

You can use the companion object scala.Boolean to "box" (in Java's sense, of course) a boolean into java.lang.Boolean:

JavaClass.varargsMethod(Boolean.box(true))

The other AnyVal classes have corresponding box methods (e.g. Int.box). There are also unbox methods to do the opposite.

A more complicated use case:

JavaClass.varargsMethod(Seq(1, 2, 3, 4).map(Int.box): _*) // passes 1, 2, 3, 4

I don't know when these were added to the standard library, but with these you don't have to use the implementation classes of scala.runtime.*.

1
votes

Note, with Scala version 2.13.x, this works out-of-the-box (no pun) without having to manually box the value.

0
votes

Probably can file a bug about it. It seems like it should throw an exception in both cases or neither. Not sure it's something that will ever be fixed as it probably is caused by some cleverness in the implementation of varargs that prevents the boxing from taking place.