Scala compiler generates wrong method signature for Tuple[Int, _] - scala

Scala compiler behaves weirdly with boxing/unboxing in tuples as parameters.
Consider the code:
scala> class Test { def test(p: (Int, String)) = println(p) }
defined class Test
scala> classOf[Test].getMethods()(0)
res2: java.lang.reflect.Method = public void Test.test(scala.Tuple2)
scala> classOf[Test].getMethods()(0).getGenericParameterTypes
res3: Array[java.lang.reflect.Type] = Array(scala.Tuple2<java.lang.Object, java.lang.String>)
scala> // WTF?????? ^^^^^^^^^^^^^^^^
Thus, I'm getting Object instead of Integer. I assume this is somehow related to tuple parameter being #specialized, but cannot wrap my head around how to avoid/fix this.
The problem it causes - it is impossible to reconstruct method parameter via reflection on method signature (e.g. while parsing json).
Even if there's a way to get the right type with scala-reflect it doesn't help much, cause there are a lot of Java libraries around (like Jersey) that use just Java reflection.
UPD:
OK, putting an Integer (instead of Int) into Tuple works ok. But why isn't it done automatically?

Related

Scala reflection with Int parameter

In the below code, I try to invoke an object's method that has an Int parameter (giving it a value of 3). This returns an error that Int and 3 are incompatible types.
//Using scala's Int does not work!
object MyObject{
def handleInt(id:Int) : Boolean = {
true
}
}
object testApp extends App {
val obj = MyObject.getClass
val method = obj.getDeclaredMethod("handleInt", classOf[Int]) //Int.getClass shows the same behavior
val rsp = method.invoke(obj, 3)
}
Error:(106, 41) the result type of an implicit conversion must be more
specific than AnyRef
val rsp = method.invoke(obj, 3)
Error:(106, 41) type mismatch; found : Int(3) required: Object
val rsp = method.invoke(obj, 3)
I tried modifying a lot of things here, the only way this could work is by changing all signatures to Java's Integer. The code will look like this:
//This works with Java's Integer
object MyObject{
def handleInt(id:Integer) : Boolean = {
true
}
}
object testApp extends App {
val obj = MyObject.getClass
val method = obj.getDeclaredMethod("handleInt", classOf[Integer])
val rsp = method.invoke(obj, 3)
}
My question(s) are:
Can someone explain why this happens? I think scala's Int wraps java's primitive int (which is why this is not considered an object), but I'm not sure.
Is there a way to achieve this using Scala's Int type?
Is it acceptable to mix scala and java types like this? Is it a good practice?
The first problem is that you invoke method on the wrong object: obj doesn't have handleInt method, MyObject does. The second is kind of an edge case: invoke takes Object... varargs and Scala doesn't automatically convert an Int directly to Object because that's not what you normally want to do. You can use a type ascription to say "box this Int into an Integer" and then Scala will upcast it to Object automatically.
So, combining these 2 fixes: you don't need to change handleInt or val method, just
val rsp = method.invoke(MyObject, 3: Integer)
To answer your final question: use of Integer, java.lang.Double, etc. shouldn't be common in Scala code, but it isn't particularly problematic. And reflection is one of the areas where you may have to use them.
No we cannot use Scala types.
Its Ok to mix Java and Scala types.
As reflection deals with reading class bytecode at Runtime. At bytecode level only types that are visible are the Java types because all scala types are boiled down to Java types.

Possible to find parameter type methods return type in Scala where parameter is a primitive type?

Suppose I have:
class X
{
val listPrimitive: List[Int] = null
val listX: List[X] = null
}
and I print out the return types of each method in Scala as follows:
classOf[ComplexType].getMethods().foreach { m => println(s"${m.getName}: ${m.getGenericReturnType()}") }
listPrimitive: scala.collection.immutable.List<Object>
listX: scala.collection.immutable.List<X>
So... I can determine that the listX's element type is X, but is there any way to determine via reflection that listPrimitive's element type is actually java.lang.Integer? ...
val list:List[Int] = List[Int](123);
val listErased:List[_] = list;
println(s"${listErased(0).getClass()}") // java.lang.Integer
NB. This seems not to be an issue due to JVM type erasure since I can find the types parameter of List. It looks like the scala compiler throws away this type information IFF the parameter type is java.lang.[numbers] .
UPDATE:
I suspect this type information is available, due to the following experiment. Suppose I define:
class TestX{
def f(x:X):Unit = {
val floats:List[Float] = x.listPrimitive() // type mismatch error
}
}
and X.class is imported via a jar. The full type information must be available in X.class in order that this case correctly fails to compile.
UPDATE2:
Imagine you're writing a scala extension to a Java serialization library. You need to implement a:
def getSerializer(clz:Class[_]):Serializer
function that needs to do different things depending on whether:
clz==List[Int] (or equivalently: List[java.lang.Integer])
clz==List[Float] (or equivalently: List[java.lang.Float])
clz==List[MyClass]
My problem is that I will only ever see:
clz==List[Object]
clz==List[Object]
clz==List[MyClass]
because clz is provided to this function as clz.getMethods()(i).getGenericReturnType().
Starting with clz:Class[_] how can I recover the element type information that was lost?
Its not clear to me that TypeToken will help me because its usages:
typeTag[T]
requires that I provide T (ie. at compile time).
So, one path to a solution... Given some clz:Class[_], can I determine the TypeTokens of its method's return types? Clearly this is possible as this information must be contained (somewhere) in a .class file for a scala compiler to correctly generate type mismatch errors (see above).
At the java bytecode level Ints have to be represented as something else (apparently Object) because a List can only contain objects, not primitives. So that's what java-level reflection can tell you. But the scala type information is, as you infer, present (at the bytecode level it's in an annotation, IIRC), so you should be able to inspect it with scala reflection:
import scala.reflect.runtime.universe._
val list:List[Int] = List[Int](123)
def printTypeOf[A: TypeTag](a: A) = println(typeOf[A])
printTypeOf(list)
Response to update2: you should use scala reflection to obtain a mirror, not the Class[_] object. You can go via the class name if need be:
import scala.reflect.runtime.universe._
val rm = runtimeMirror(getClass.getClassLoader)
val someClass: Class[_] = ...
val scalaMirrorOfClass = rm.staticClass(someClass.getName)
// or possibly rm.reflectClass(someClass) ?
val someObject: Any = ...
val scalaMirrorOfObject = rm.reflectClass(someObject)
I guess if you really only have the class, you could create a classloader that only loads that class? I can't imagine a use case where you wouldn't have the class, or even a value, though.

Why can a Map object be created without an apply-method?

C:\Users\John>scala
Welcome to Scala version 2.9.2 (Java HotSpot(TM) Client VM, Java 1.6.0_32).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map
scala> Map()
res4: scala.collection.mutable.Map[Nothing,Nothing] = Map()
When using Map() without keyword new the apply method from the corresponding companion object will be called. But the Scala Documentation does not list an apply method for mutable Maps (only an apply method to retrieve a value from the map is provided).
Why is the code above still working ?
It looks like a bug in scaladoc. There is an apply method in object collection.mutable.Map (inherited from GenMapFactory) but it does not appear in the doc for Map. This problem seems to be fixed in the doc for upcomping 2.10.
Note : you must look into the object documentation, not the class one. The method apply in the class of course works with an existing map instance, and retrieve data from it.
There is an apply() method on the companion object of scala.collection.immutable.Map(). It is inherited from scala.collection.MapFactory . That method takes a variable number of pair arguments, and is usually used as
Map("foo"->3, "bar"->4, "barangus"->5)
Calling it with no arguments evidently works as well, but someone brighter than me would have to explain why the type inference engine comes up with scala.collection.mutable.Map[Nothing,Nothing] for it.
As sepp2k already mentioned in his comment the symbol Map refers to the companion object of Map, which gives you access to its single instance. In patter-matching this is often used to identify a message:
scala> case object Foo
defined module Foo
scala> def send[A](a: A) = a match { case Foo => "got a Foo" case Map => "got a Map" }
send: [A](a: A)String
scala> send(Map)
res8: String = got a Map
scala> send(Foo)
res9: String = got a Foo
If you write Map() you will call the apply method of object Map. Because you did not give any values to insert into the Map the compiler can't infer any type, thus it has to use the bottom type - Nothing - which is a subtype of every type. It is the only possible type to infer which will not break the type system although there are variances. Would Nothing not exist the following code would not compile:
scala> Map(1 -> 1) ++ Map()
res10: scala.collection.mutable.Map[Int,Int] = Map(1 -> 1)
If you take a look to the type signature of ++ which is as follows (source)
def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1]
you will notice the lower-bound type parameter B1 >: B. Because Nothing is a subtype of everything (and B in our case) the compiler can find a B1 (which is Int in our case) and successfully infer a type signature for our Map. This lower-bound is needed because B is covariant (source),
trait MapLike[A, +B, ...] ...
which means that we are not allowed to deliver it as a method parameter (because method parameters are in contravariant position). If the method parameters would not be in contravariant position Liskov's substitution principle would no longer kept by the type system. Thus to get the code to compile a new type (here called B1) has to be found.
As Didier Dupont already pointed out there are some bugs in Scaladoc 2.9, which are solved in 2.10. Not only some missed methods are displayed there but also methods added by an implicit conversion can be displayed (Array for example does display a lot of methods in 2.10 which are not displayed in 2.9).

Scala partially applied type constructor inference

I'm using scala-2.8.1 and scalaz-5.0. Can anyone explain exactly why a PartialApply1Of2 can be inferrred in the one case but not in the other?
scala> 1.success[String] <|*|> "Bah".fail[Int]
res1: scalaz.Validation[String,(Int, Int)] = Failure(Bah)
That worked even though (as has been asked before!) the method <|*|> is on MA which has one type parameter, not two (as Validation has). I cannot get unicode working in my IDEA REPL, so here goes:
object testy {
def main(args: Array[String]) {
import scalaz._
import Scalaz._
val ps = NonEmptyList(1.success[String], "Bah".fail[Int])
val res = ps.∘∘((_ : Int) % 2 == 0) //DOES NOT COMPILE
println(res)
}
}
I can provide a specific type to the call and all is good. Why can scalac not infer this?
ps.∘∘[PartialApply1Of2[Validation, String]#Apply, Int, Boolean]((_ : Int) % 2 == 0)
In my REPL, this actually causes a scalac error, rather than a sensible error message
In the first case, the implicit view ValidationMA is inferred, and the the type argument Int is inferred:
Scalaz.ValidationMA(1.success[String]).<|*|>[Int]("Bah".fail[Int])
In the second case, the type argument to the method ∘∘ cannot be inferred, until #2712 is tackled.
I suspect that the scalac internal error you encountered is related to #2741 / #4079. If so, you can rewrite it with a Type Lambda to workaround the error.
ps.∘∘[({type X[a]=Validation[String, a]})#X, Int, Boolean]((_ : Int) % 2 == 0)
I recommend using this syntax instead of PartialApplyNofM in all cases, as I find it more readable. With a recent build of IntelliJ, you can even enable a code folding (Settings, Code Style, Scala, Folding, Type Lambas), to hide some syntactic clutter.

Spurious ambiguous reference error in Scala 2.7.7 compiler/interpreter?

Can anyone explain the compile error below? Interestingly, if I change the return type of the get() method to String, the code compiles just fine. Note that the thenReturn method has two overloads: a unary method and a varargs method that takes at least one argument. It seems to me that if the invocation is ambiguous here, then it would always be ambiguous.
More importantly, is there any way to resolve the ambiguity?
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._
trait Thing {
def get(): java.lang.Object
}
new MockitoSugar {
val t = mock[Thing]
when(t.get()).thenReturn("a")
}
error: ambiguous reference to overloaded definition,
both method thenReturn in trait OngoingStubbing of type
java.lang.Object,java.lang.Object*)org.mockito.stubbing.OngoingStubbing[java.lang.Object]
and method thenReturn in trait OngoingStubbing of type
(java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object]
match argument types (java.lang.String)
when(t.get()).thenReturn("a")
Well, it is ambiguous. I suppose Java semantics allow for it, and it might merit a ticket asking for Java semantics to be applied in Scala.
The source of the ambiguitity is this: a vararg parameter may receive any number of arguments, including 0. So, when you write thenReturn("a"), do you mean to call the thenReturn which receives a single argument, or do you mean to call the thenReturn that receives one object plus a vararg, passing 0 arguments to the vararg?
Now, what this kind of thing happens, Scala tries to find which method is "more specific". Anyone interested in the details should look up that in Scala's specification, but here is the explanation of what happens in this particular case:
object t {
def f(x: AnyRef) = 1 // A
def f(x: AnyRef, xs: AnyRef*) = 2 // B
}
if you call f("foo"), both A and B
are applicable. Which one is more
specific?
it is possible to call B with parameters of type (AnyRef), so A is
as specific as B.
it is possible to call A with parameters of type (AnyRef,
Seq[AnyRef]) thanks to tuple
conversion, Tuple2[AnyRef,
Seq[AnyRef]] conforms to AnyRef. So
B is as specific as A. Since both are
as specific as the other, the
reference to f is ambiguous.
As to the "tuple conversion" thing, it is one of the most obscure syntactic sugars of Scala. If you make a call f(a, b), where a and b have types A and B, and there is no f accepting (A, B) but there is an f which accepts (Tuple2(A, B)), then the parameters (a, b) will be converted into a tuple.
For example:
scala> def f(t: Tuple2[Int, Int]) = t._1 + t._2
f: (t: (Int, Int))Int
scala> f(1,2)
res0: Int = 3
Now, there is no tuple conversion going on when thenReturn("a") is called. That is not the problem. The problem is that, given that tuple conversion is possible, neither version of thenReturn is more specific, because any parameter passed to one could be passed to the other as well.
In the specific case of Mockito, it's possible to use the alternate API methods designed for use with void methods:
doReturn("a").when(t).get()
Clunky, but it'll have to do, as Martin et al don't seem likely to compromise Scala in order to support Java's varargs.
Well, I figured out how to resolve the ambiguity (seems kind of obvious in retrospect):
when(t.get()).thenReturn("a", Array[Object](): _*)
As Andreas noted, if the ambiguous method requires a null reference rather than an empty array, you can use something like
v.overloadedMethod(arg0, null.asInstanceOf[Array[Object]]: _*)
to resolve the ambiguity.
If you look at the standard library APIs you'll see this issue handled like this:
def meth(t1: Thing): OtherThing = { ... }
def meth(t1: Thing, t2: Thing, ts: Thing*): OtherThing = { ... }
By doing this, no call (with at least one Thing parameter) is ambiguous without extra fluff like Array[Thing](): _*.
I had a similar problem using Oval (oval.sf.net) trying to call it's validate()-method.
Oval defines 2 validate() methods:
public List<ConstraintViolation> validate(final Object validatedObject)
public List<ConstraintViolation> validate(final Object validatedObject, final String... profiles)
Trying this from Scala:
validator.validate(value)
produces the following compiler-error:
both method validate in class Validator of type (x$1: Any,x$2: <repeated...>[java.lang.String])java.util.List[net.sf.oval.ConstraintViolation]
and method validate in class Validator of type (x$1: Any)java.util.List[net.sf.oval.ConstraintViolation]
match argument types (T)
var violations = validator.validate(entity);
Oval needs the varargs-parameter to be null, not an empty-array, so I finally got it to work with this:
validator.validate(value, null.asInstanceOf[Array[String]]: _*)