scala> val a = Int
a: Int.type = object scala.Int
scala> val a = String
<console>:11: error: object java.lang.String is not a value
val a = String
^
Why didn't scala create a thin wrapper around java.lang.String in order to make String a value? Isn't it very restrictive when one of the main types (String) cannot be used in expressions or passed to / returned from functions?
Well... In Scala class's can have companion objects.
And that companion object for any class A is actually an instance of A.type.
So... when you do,
val i = Int
What you get is companion object of class Int which is an instance of Int.type
Keep in mind that Int is still not a value... this thing that you have is not Int. It is also not an instance of Int. It is an instance of Int.type.
But as far as String is concerned... it is defined as an Alias for the corresponding java.lang.String from the Java world and thus has no such companion object. And hence the val assignment does not work with it.
As for why String is not wrapped in Scala. There can be many reasons for this. But one main reason is because there was no need for that.
Scala wanted to be have pure object hierarchy such that everything is an object and inherits from the same root Any. And Java has basic-types like int, long etc... which are not objects... and this created a need to wrap them into Int.
Although the question probably turns on a misapprehension about reifying a type, the following suggests why you can select Java statics as though they were members of a companion object, even though there is no such object:
$ scala
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> java.lang.System.currentTimeMillis
res0: Long = 1483263161912
scala> java.lang.System
<console>:12: error: object java.lang.System is not a value
java.lang.System
^
scala> java.lang.System.toString
<console>:12: error: value toString is not a member of object System
Note that System extends Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
java.lang.System.toString
^
scala>
Related
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?
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.
As I read in some good Scala books the method declared in Scala REPL are not function(They are not values). They are method.So I want to know exactly which object is consumer that method call.
eg when I call println it is syntatic sugar of Predef.println which under the hood call Console.println . So when I define
def sayHello = "Hello"
then on which object it is being called ,means obj.sayHello what obj is ?
Thanks
It looks like REPL does the following if you execute a line:
It wraps it into an anonymous object literal, imports the members of all previously generated objects and compiles that. If the line has a return value, it includes a member resX to that object and stores the return value there.
You can see that by executing stuff like this.
scala> def foo = "asd"; this
foo: String
res0: type = #ee7d9f1
scala> res0.foo
res1: String = asd
scala> def foo = this; this
foo: type
res2: type = #6d86b085
scala> res2.foo
res3: type = #6d86b085
scala> res3.foo.res2.foo.foo.res2
res4: type = #6d86b085
The interesting thing is the type of these objects, its "type", and the class of the objects has an empty name. This does not usually happen, maybe it is, what the compiler API generates, if you just give it a line of code that is not wrapped in any context, something, you normally cannot do in Scala.
If you really want to know it exactly, you probably have to look into the source of Scala. But to use REPL it should be enough to know, that your code is wrapped in a fresh anonymous object each time.
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.
For purposes of my app I need to be able to find out a list of fields of a type (not an instance) and types of those fields in runtime. So far I was only able to get a list of methods of a case class containing getters with classOf[MyCaseClass].getMethods and nothing useful from a simple class. Am I missing something? Are there any reflection libraries for that kinda purposes? How's that done correctly?
Using Scala 2.10 reflection:
scala> import reflect.runtime.{universe => ru}
import reflect.runtime.{universe=>ru}
scala> trait A { val field1: Int; val field2: Char; def meth1: Int }
defined trait A
scala> val fieldSymbols = ru.typeOf[A].members.collect{ case m: ru.MethodSymbol if m.isGetter => m }
fieldSymbols: Iterable[reflect.runtime.universe.MethodSymbol] = List(value field2, value field1)
The returned symbols contain all the type information, e.g.:
scala> fieldSymbols.map(_.typeSignature)
res16: Iterable[reflect.runtime.universe.Type] = List(=> scala.Char, => scala.Int)
You may want to take a look at this document on reflecting scala. getMethods is a method from Java reflection. What can't you find there? From the Javadoc:
String getName(): Returns the name of the method represented by this Method object, as a String.
Class[] getParameterTypes(): Returns an array of Class objects that represent the formal parameter types, in declaration order, of the method represented by this Method object.
Class getReturnType(): Returns a Class object that represents the formal return type of the method represented by this Method object.
You could read more about Java reflection.
Note that not all type information will be available at runtime because of erasure.