def test[T: ClassTag]: T = {
println(classTag[T])
null.asInstanceOf[T]
}
val x1: Int = test
val x2: Int = test[Int]
prints
Nothing
Int
I would expect the compiler to guess the Int type without the need to provide it explicitly (EDIT: on the right hand side, i.e. make val x1: Int = test work).
Is there perhaps a workaround to get rid of the explicit type annotation?
I suspect that compiler can't infer Int in val x1: Int = test[???] because both options:
val x1: Int = test[Int] // returns Int
and
val x1: Int = test[Nothing] // returns Nothing <: Int
are valid. So compiler just has to guess what option you meant.
When compiler has a choice it often selects the minimal type out of the options. And currently this is Nothing.
Why Scala Infer the Bottom Type when the type parameter is not specified?
In principle, if you'd like to explore the type of left hand side you can make test a macro. Then it can be even not generic. Making it whitebox means that it can return a type more precise than declared (Any) e.g. Int.
import scala.reflect.macros.whitebox // libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
import scala.language.experimental.macros
def test: Any = macro testImpl
def testImpl(c: whitebox.Context): c.Tree = {
import c.universe._
val T = c.internal.enclosingOwner.typeSignature
println(s"T=$T")
q"""
_root_.scala.Predef.println(_root_.scala.reflect.runtime.universe.typeOf[$T])
null.asInstanceOf[$T]
"""
}
// in a different subproject
val x1: Int = test // prints at runtime: Int
// scalacOptions += "-Ymacro-debug-lite"
//scalac: T=Int
//scalac: {
// _root_.scala.Predef.println(_root_.scala.reflect.runtime.universe.typeOf[Int]);
// null.asInstanceOf[Int]
//}
Actually there's nothing wrong with type inference here, type inference here means that the compiler should figure out that the T type parameter is Int, and the returned value from your method expression is an integer, and that's working properly:
x1: Int = 0 // this is the result of your first line
You can also try printing this:
println(x1.getClass) // int
What's not working as expected is implicit resolution for a generic type "ClassTag[_]". The reason it prints Nothing is that the compiler found the object scala.reflect.ClassTag.Nothing : ClassTag[Nothing] suitable for your case. Now about this new thing, there are loads of content on SO and the internet for why this happens and how to deal with it in different cases.
Here's another piece of code to differentiate type inference with type erasure in your case:
def nullAs[T]: T = null.asInstanceOf[T]
val int: Int = nullAs // 0: Int
// type erasure:
case class Container[T](value: T)
implicit val charContainer: Container[Char] = Container('c')
def nullWithContainer[T](implicit container: Container[T]): T = {
println(container)
null.asInstanceOf[T]
}
val long: Long = nullWithContainer
// prints Container(c)
// 0L
Which means type inference is done correctly, but type erasure has happened, because in runtime, the type of charContainer is Container, not Container[Char].
val x1: Int = test
In this line, the Int you have given is the type for the value x1 which would hold the result of the function test and as for the classTag of T the compiler finds no information which is why it returns Nothing, in which case its taking val x1: Int = test[Nothing] so you would always have to mention a Type for test else it would print Nothing
Related
I have this piece of code
import scala.util.Try
val t: Try[Unit] = Try(Try(1))
and 2 questions:
What is happening here? How can the type Try[Try[Int]] match with
Try[Unit]? Is it because Scala chooses the return type for block
Try(1) to be Unit to match with the desired type?
Is there anyway to detect a nested Try? Says I have a Try[A], how do I know if A is another Try[_]?
You are basically forcing compiler to assign Try as Unit.
For exmple doSomething method below is supposed to return Int as that is last statement, but return type Unit is forcing it to return ().
scala> def doSomething: Unit = 1 + 1
doSomething: Unit
In your example val t: Try[Unit] = Try(Try(1 / 0)), you asking compiler to treat inner Try(1 / 0) as Unit; which means
scala> val innerTry: Unit = Try(1 / 0)
innerTry: Unit = ()
Which means even if Try fails, its Unit which is always Success for another Try that you have.
scala> val t: Try[Unit] = Try(someOperation)
t: scala.util.Try[Unit] = Success(())
Better remove the specific type you are providing and let the compiler figure it out,
scala> val t = Try(Try(1 / 0))
t: scala.util.Try[scala.util.Try[Int]] = Success(Failure(java.lang.ArithmeticException: / by zero))
Also read: Scala: Why can I convert Int to Unit?
final abstract class Unit private extends AnyVal {
// Provide a more specific return type for Scaladoc
override def getClass(): Class[Unit] = ???
}
Try(1) returns Success(1).
Try(Try(1) returns Success(())because of its assignment to Type Try[Unit]
Similar to the following commands in Scala REPL where x is forced to take Unit type:
scala> val x = 5
x: Int = 5
scala> val x:Unit = 5
<console>:23: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
val x:Unit = 5
^
x: Unit = ()
scala>
So obviously the compiler is taking the return value and is forced to type () which is Unit.
Because it is Unit may be it makes sense the way compiler interprets it.
For the following code:
object Test {
class MapOps(map: Map[String, Any]) {
def getValue[T](name: String): Option[T] = {
map.get(name).map{_.asInstanceOf[T]}
}
}
implicit def toMapOps(map: Map[String, Any]): MapOps = new MapOps(map)
def main(args: Array[String]): Unit = {
val m: Map[String, Any] = Map("1" -> 1, "2" -> "two")
val a = m.getValue[Int]("2").get.toString
println(s"1: $a")
val b = m.getValue[Int]("2").get
println(s"2: $b")
}
}
val a is computed without exception and the console prints 1: two,
but when computing val b, the java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer is thrown.
Besides, if I execute
val c = m.getValue[Int]("2").get.getClass.toString
println(s"1: $c")
The console prints "int".
Can someone explain why this code behaves like this?
This is certainly odd.
If you look at the following statement in the Scala REPL:
scala> val x = m.getValue[Int]("2")
x: Option[Int] = Some(two)
What I think is happening is this: the asInstanceOf[T] statement is simply flagging to the compiler that the result should be an Int, but no cast is required, because the object is still just referenced via a pointer. (And Int values are boxed inside of an Option/Some) .toString works because every object has a .toString method, which just operates on the value "two" to yield "two". However, when you attempt to assign the result to an Int variable, the compiler attempts to unbox the stored integer, and the result is a cast exception, because the value is a String and not a boxed Int.
Let's verify this step-by-step in the REPL:
$ scala
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_151).
Type in expressions for evaluation. Or try :help.
scala> class MapOps(map: Map[String, Any]) {
| def getValue[T](name: String): Option[T] = {
| map.get(name).map{_.asInstanceOf[T]}
| }
| }
defined class MapOps
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
scala> implicit def toMapOps(map: Map[String, Any]): MapOps = new MapOps(map)
toMapOps: (map: Map[String,Any])MapOps
scala> val a = m.getValue[Int]("2").get.toString
a: String = two
scala> println(s"1: $a")
1: two
So far so good. Note that no exceptions have been thrown so far, even though we have already used .asInstanceOf[T] and used get on the resulting value. What's significant is that we haven't attempted to do anything with the result of the get call (nominally a boxed Int that is actually the String value "two") except to invoke it's toString method. That works, because String values have toString methods.
Now let's perform the assignment to an Int variable:
scala> val b = m.getValue[Int]("2").get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
... 29 elided
Now we get the exception! Note also the function in the stack trace that caused it: unboxToInt - it's clearly trying to convert the value stored in the Some to an Int and it fails because it's not a boxed Int but a String.
A big part of the problem is type erasure. Don't forget that a Some(Banana) and a Some(Bicycle) are - at runtime - both just Some instances with a pointer to some object. .asInstanceOf[T] cannot verify the type, because that information has been erased. However, the compiler is able to track what the type should be based upon what you've told it, but it can only detect the error when its assumptions are proven wrong.
Finally, with regard to the getClass call on the result. This is a bit of compiler sleight-of-hand. It's not actually calling a getClass function on the object, but - because it thinks it's dealing with an Int, which is a primitive - it simply substitutes an int class instance.
scala> m.getValue[Int]("2").get.getClass
res0: Class[Int] = int
To verify that the object actually is a String, you can cast it to an Any as follows:
scala> m.getValue[Int]("2").get.asInstanceOf[Any].getClass
res1: Class[_] = class java.lang.String
Further verification about the return value of get follows; note the lack of an exception when we assign the result of this method to a variable of type Any (so no casting is necessary), the fact that the valid Int with key "1" is actually stored under Any as a boxed Int (java.lang.Integer), and that this latter value can be successfully unboxed to a regular Int primitive:
scala> val x: Any = m.getValue[Int]("2").get
x: Any = two
scala> x.getClass
res2: Class[_] = class java.lang.String
scala> val y: Any = m.getValue[Int]("1").get
y: Any = 1
scala> y.getClass
res3: Class[_] = class java.lang.Integer
scala> val z = m.getValue[Int]("1").get
z: Int = 1
scala> z.getClass
res4: Class[Int] = int
Expanding on the last part of eje211's answer.
You told the compiler that a String was an Int, and now you're looking for a sensible explanation of the resulting behavior. That's understandable, but it's not really useful. Once you tell the compiler a lie, all bets are off. You can spend time investigating exactly when and where the compiler inserts checks that happen to discover your deceit, but your time would probably be better spent writing code that doesn't cause you to lie.
As the earlier answer pointed out, you can do that (avoid accidental lying) by using pattern matching. You'll need a ClassTag to make pattern matching work in cases like the above, but the end result will be code that is type-safe and correct.
It's an Int because you request an Int on this line :
val b = m.getValue[Int]("2").get
This calls this method:
def getValue[T](name: String): Option[T] = {
map.get(name).map{_.asInstanceOf[T]}
}
and applies it this way:
def getValue[Int](name: String): Option[Int] = {
map.get(name).map{_.asInstanceOf[Int]}
}
So if you ask for an Int, you get an Int.
In the case of "two", this is what happens in that case:
"two".asInstanceOf[Int]
That's what throws your exception.
A String is not an Int. You can't cast it that way. You can cast it this way:
"2".toInt
But that's different.
In general, using asInstanceOf[] is dangerous. Try pattern matching instead. If you must use, it's up you to make sure that the casts you attempt are valid. You're basically telling the compiler to bypass its own type-checks, particularly when you cast from Any.
It works when you add .toString because then, you change the type back to String, which is what it really was in the first place. The lie of what type the data was is corrected.
By assigning a variable (or value?) a method name with a space and an underscore, you tell scala to treat the method as a function, which apparently means doing more than simply taking the value generated by a call to the method and assigning to the variable. What else is/can go on through such an assignment?
Since Scala runs on the JVM, it's easier to understand in terms of simple Java-like classes without Scala's syntactic sugar.
Remember that Scala functions are essentially members of a class similar to the following (signature deliberately simplified):
class Function[X, Y] {
def apply(x: X): Y
}
Application of a function f to an argument x is desugared into a method application f.apply(x).
Now suppose that you have another class Foo with method bar:
class Foo {
def bar(x: Int): String
}
If you now have an instance foo of type Foo, then whenever its method bar is transformed into a function by writing:
val f = foo.bar(_)
a new instance of an anonymous subclass of Function is created:
val f = new Function[Int, String] {
def apply(x: Int) = foo.bar(x)
}
If you use this syntax inside a class, this is closed over instead of an instance foo.
This is what all those weirdly named classes Main$$anon$1$$anonfun$1 are: they are the anonymous classes that represent functions. The functions can appear quite implicitly (for example, as blocks passed to the for-loops).
That's all there is to it semantically. The rest is just syntactic sugar.
Here is a complete runnable example that demonstrates the conversion of an instance method into a function:
with sugar, from the outside (a)
with sugar, from the inside (b)
without sugar, from the outside (c)
without sugar, from the inside (d)
You can save it into a file and execute with scala <filename.scala>:
/** A simple greeter that prints 'hello name' multiple times */
case class Hey(name: String) { thisHeyInst =>
def hello(x: Int): String = ("hello " + name + " ") * x
def withSugarFromInside = hello(_)
def noSugarFromInside = new Function[Int, String] {
def apply(y: Int) = thisHeyInst.hello(y)
}
}
val heyAlice = Hey("Alice")
val heyBob = Hey("Bob")
val heyCharlie = Hey("Charlie")
val heyDonald = Hey("Donald")
val a = heyAlice.hello(_)
val b = heyBob.withSugarFromInside
val c = new Function[Int, String] { def apply(y: Int) = heyCharlie.hello(y) }
val d = heyDonald.noSugarFromInside
println(a(3))
println(b(3))
println(c(3))
println(d(3))
In all four cases, a greeting is printed three times.
What _ actually does is an eta-conversion. It takes compile-time construction called method and returns runtime construction called anonymous function, which is actually an instance of scala's Function. Exactly the class depends on arity, so it might be Function1, Function2, Function3 and so on. The point here is to make First-class citizen, which may act like a value.
OOP needs a little more than some new object. Before making the code that creates instance, compiler generates a new class (extending FunctionN) in compile-time, but theoretically it shouldn't be necessary a whole new class. For Java 8 it could be native Java-lambdas.
Btw, you may extend Function1 by yourself and even eta-abstract it again:
scala> object f extends (Int => Int) { def apply(a: Int) = a }
scala> f(1)
res0: Int = 1
scala> f.apply _
res1: Int => Int = <function1>
scala> res1(5)
res2: Int = 5
As a conclusion a little copy-paste from #Daniel C. Sobral's answer:
the former can be easily converted into the latter:
val f = m _
Scala will expand that, assuming m type is (List[Int])AnyRef
into (Scala 2.7):
val f = new AnyRef with Function1[List[Int], AnyRef] {
def apply(x$1: List[Int]) = this.m(x$1)
}
On Scala 2.8, it actually uses an AbstractFunction1 class to reduce
class sizes.
Or simply saying val f = m _ is same as val f = (x: List[Int]) => m(x)
To make this answer more modern and precise let's see what's happening using scalac 2.11.2 and javap:
$ echo "object Z{def f(a: Int) = a}" > Z.scala //no eta-abstraction here
$ scalac Z.scala
$ ls
Z$.class Z.class Z.scala
$ echo "object Z{def f(a: Int) = a; val k = f _}" > Z.scala
$ scalac Z.scala
$ ls
Z$$anonfun$1.class Z.class //new anonfun class added for lambda
Z$.class Z.scala
$ javap -c Z\$\$anonfun\$1.class
Compiled from "Z.scala" // I've simplified output a bit
public final class Z$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp implements scala.Serializable {
public final int apply(int);
Code:
calling apply$mcII$sp(int)
public int apply$mcII$sp(int); //that's it
Code:
0: getstatic #25 // reading Field Z$.MODULE$:LZ$;, which points to `object Z`
3: iload_1
4: invokevirtual #28 // calling Method Z$.f
7: ireturn
public final java.lang.Object apply(java.lang.Object); //just boxed version of `apply`
Code:
unboxToInt
calling apply(int) method
boxToInteger
public Z$$anonfun$1();
Code:
AbstractFunction1$mcII$sp."<init>":()V //initialize
}
So it still extends AbstractFunction1
I'll try to provide some examples how a function or method are assigned to values with underscore.
If it's need to reference a zero-argument function
scala> val uuid = java.util.UUID.randomUUID _
uuid: () => java.util.UUID = <function0>
scala> uuid()
res15: java.util.UUID = 3057ef51-8407-44c8-a09e-e2f4396f566e
scala> uuid()
uuid: java.util.UUID = c1e934e4-e722-4279-8a86-004fed8b9090
Check how it's different when one does
scala> val uuid = java.util.UUID.randomUUID
uuid: java.util.UUID = 292708cb-14dc-4ace-a56b-4ed80d7ccfc7
In first case one assigned a reference to a function. And then calling uuid() generates new UUID every time.
In second, function randomUUID has been called and value assigned to a val uuid.
There are some other cases why _ might be useful.
It's possible to use a function with two arguments and create a function with a single argument out of it.
scala> def multiply(n: Int)(m: Int) = n*m
multiply: (n: Int)(m: Int)Int
scala> val by2 = multiply(2) _
by2: Int => Int = <function1>
scala> by2(3)
res16: Int = 6
To be able to do, it's crucial to define function multiply as curried. It's called function currying.
I'm intrigued by the following Scala compiler behavior. When i declare a function of type unit, but nevertheless provide as body a function that evaluate to an Int, the Scala compiler is ok with it.
def add(x:Int, y:Int) = x + y
def main(args: Array[String]): Unit = {add(args(0).toInt, args(0).toInt)}
While the same is not true with other type such in
def afunc: String = {1} //type mismatch; found : Int(1) required: String
Also if i write
def afunc: Unit = {1}
or
def main(args: Array[String]): Unit = {2 + 2} // Which is just like the first addition above
In both case i get the following warning:
a pure expression does nothing in statement position; you may be omitting necessary parentheses
In a sense there is 2 questions here. What is the difference between a function that return evaluate to an Int and the expression 2 + 2. Then why on earth, the compiler does not complain that a function that is suppose to evaluate to Unit, gets a body that evaluate to another type, as it would happens between other types.
Many thanks in advance,
Maatari
What is the difference between a function that return evaluate to an
Int and the expression 2 + 2.
A function that evaluates to an Int might have side effects
var a = 0
def fn: Int = {
a = a + 1
1
}
Every call to fn changes the value of a.
Then why on earth, the compiler does not complain that a function that
is suppose to evaluate to Unit, gets a body that evaluate to another
type, as it would happens between other types.
When you specify Unit as the return type the compiler does an implicit conversion from whatever value the function returns to Unit (there is only one Unit value as it is an object, you can think of it as the void type of Scala).
Unit is inferred as a return type for convenience. For example,
scala> val h = new collection.mutable.HashMap[String,String]
h: scala.collection.mutable.HashMap[String,String] = Map()
scala> h += "fish" -> "salmon"
res1: h.type = Map(fish -> salmon)
we see that the += method on mutable HashMaps returns the map.
But if you don't infer unit, then
def add(a: String, b: String): Unit = h += a -> b
doesn't work.
Which thing is worse--accidentally expecting a return value vs. demanding you explicitly return the most boring possible return value--depends on how functional your code is. If you have more than a few side-effects, not inferring Unit is rather painful.
A function with just the parentheses is mainly called for the side-effects. It may return a result, as it was common in the days of C or Java but in reality we don't care, cause we will not use it.
{} is equivalent to : Unit =, and the annotation of return type can be seen as a cast or an implicit conversion to match the type expected by the function.
Here is another example where this behavior occurs.
def add(a: Int, b:Int) : Double = a + b
add: (a: Int, b: Int)Double
scala> add(4,5)
res17: Double = 9.0
Thus it seems that every value can be transformed to unit.
scala> val a: Unit = 1:Unit
<console>:28: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
val a: Unit = 1:Unit
^
a: Unit = ()
I am wondering why the two type parameters (named "A") with the same name ("A") is allowed as per the example below. I know this is a POOR naming of type parameters, don't do this.
(My guess is that they are on a on a different scope level, e.g. class level and function level, and the compiler is using some kind of name mangling)
class MyTest[A](){
type MyType = A
def checkString[A](value:A, x:MyType):A = {
value match {
case x:String => println("Value is a String")
case _ => println("Value is not a String")
}
x match {
case x:String => println("x is a String")
case _ => println("x is not a String")
}
value
}
}
Example output from 2.8.0
scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest#308ff65f
scala> test.checkString("String",1)
Value is a String
x is not a String
res7: java.lang.String = String
scala> test.checkString(1,1)
Value is not a String
x is not a String
res8: Int = 1
Nested scopes in Scala are free to shadow each others' symbol tables. Types are not the only things you can do this with. For example:
class X[A](a: A) {
def X[A](a: A) {
if (a==this.a) {
val X = Some(this.a)
X match {
case Some(a) => "Confused much yet?"
case _ => "Just because you can do this doesn't mean you should."
}
}
}
}
The principle is that a scope has control over its namespace. This has dangers, if you use it foolishly (e.g. I have used X and a for each of three different things, and A for two--in fact, you could replace every identifier with X except for the one in the Some which has to be lower case). But it also has benefits when writing functional code--you don't have to worry about having to rename some iterating variable or type or whatever just because you happen to place it in a different context.
def example = {
val a = Array(1,2,3,4,5)
val sumsq = a.map(i => i*i).sum
a.map(i => {
val a = Array.range(1,i)
val sumsq = a.map(i => i*i).sum // Cut and paste from above, and works!
sumsq + i
}).sum
}
So be aware that you have the power to confuse yourself, and wisely choose to use that power non-confusingly.
I'm not expert of Scala, but your code behave exactly what I would expected.
First, you need to know that the type parameter of method is not need bound to class.
For example, the following is valid Scala.
class Test1 {
def test[A] (x: A) = println(x)
}
And the following is also a valid Scala code, the only different is that this one does not use the type A at all.
class Test2[A] {
def test (x: Int) = println(x)
}
So I think it is clear now, first you created a instance of MyTest[Int], which is fine.
scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest#308ff65f
Then you called checkString[A, Int] without provide type parameter A, since it is a generic function, the compiler must inference what type is A.
scala> test.checkString("String",1)
Value is a String
x is not a String
res7: java.lang.String = String
Note:
In this time point, Scala already knows that x must be a Int and its type is fixed, since you provide it by MyTest[Int]. So the following code will yield compile error.
scala> val t = new MyTest[Int]
t: MyTest[Int] = MyTest#cb800f
scala> t.checkString ("A", "B")
<console>:8: error: type mismatch;
found : java.lang.String("B")
required: t.MyType
t.checkString ("A", "B")
Now the complier looks at the arguments you provided, and found its is
checkString ("String", 1)
which is corresponding to
checkString (value: A, x: Int)
So now compiler knows type A in checkString[A, Int] must be a string, and if you do all of this by hand, your code will look like this.
scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest#5bda13
scala> test.checkString[String]("String", 1)
Value is a String
x is not a String
res1: String = String
scala> test.checkString[Int] (3, 4)
Value is not a String
x is not a String
res4: Int = 3
scala> test.checkString[Int] ("String", 4)
<console>:8: error: type mismatch;
found : java.lang.String("String")
required: Int
test.checkString[Int] ("String", 4)
^
Well I belive at scala we use same rule as in Java basically we are looking for smallest available scope in Java:
class Foo<T>{
T instance;
void <T> T getInstance(){
return instance
}
}
Will produce a compilation error since type T declared in generic method getInstance is not the same as parameter type of class Foo.
In case of Scala I believe then you write
def checkString[A]
You telling compiler that function behavior will vary upon provided type but it has no connection with parameter class of outer class. Unfortunately I cannot find correct place is Scala spec right now.
Its not just related to scala. In most languages you can do that. Because as you said the variables are in different scope.
In c#
class test
{
int i;
void method(int i)
{
this.i = i;
}
}
this represents the self type. I am not sure about the this functionality in scala. But the reason for your question is scope level.