Here are two REPL sessions (inspired by this question, although my question is different):
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def ignore(it: String) = 42
ignore: (it: String)Int
scala> ignore(null.asInstanceOf[Nothing])
res0: Int = 42
And:
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def ignore(it: String) = 42
ignore: (it: String)Int
scala> ignore(null.asInstanceOf[Nothing])
java.lang.NullPointerException
at .<init>(<console>:9)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
The only difference is that the first is Scala 2.9.2 and the second is 2.10.0.
Can someone point to the changes in 2.10 that lead to this new behavior?
I know that casting to Nothing is a silly thing to do, and that the answer might be "this is all undefined behavior so just stop doing that", but it looks like the kind of thing that could potentially have implications for upgraders, and I don't remember running into any discussions of changes that would explain this.
Since Scala treats null differently from the None case on an option, even a null value of Nothing is problematic--there should be exactly zero instances of Nothing, not one instance that may or may not break depending on how you use it.
Thus, I cannot see how the old behavior is anything but a bug. It should be mentined in the release notes that it was fixed, but relying on .asInstanceOf[Nothing] to do anything save throw an exception is sufficiently contrary to type-sanity that I don't think anything more is needed. (In fact, I don't even think the release note is needed.)
This looks like an issue just with the console, not with the language. If you run this small application which invokes the exact same method, scala 2.10 doesn't have a problem with it.
object Test extends App {
override def main(args: Array[String]) {
println(takesString(null.asInstanceOf[Nothing]))
}
def takesString(a: String) = 42
}
To simplify your example from above, you could just type
null.asInstanceOf[Nothing]
and the console would give you the same error. I presume it has something to do with printing out the type.
Update: Looks like I accidentally ran against 2.9.2. Still fails as a script in 2.10 RC5 as the author points out in comment.
I know you are not expecting the answer "this is all undefined behavior, so (...)", but when you add "thing that could potentially have implications for upgraders", I must remember (even if it's obvious) that people can't rely or expect anything of the result of a thing that has undefined behavior, by its own definition.
In the specific case you mentioned, I don't think it is undefined behavior: it should throw an exception. Nothing is a subclass of Null, not the other way around - my first expectation, without testing, was that the line null.asInstanceOf[Nothing] would throw a ClassCastException, as null is not a Nothing. However, you can see that null is a special instance (as it is in Java). Try running:
scala> "aaa".asInstanceOf[Nothing]
java.lang.ClassCastException: java.lang.String cannot be cast to scala.runtime.N
othing$
at .<init>(<console>:8)
at .<clinit>(<console>)
My guess is that it happens because internally, obj.asInstanceOf[T] calls obj.getClass() in order to check the cast at runtime. As calling any method on null throws a NullPointerException, that exception is thrown before ClassCastException.
Back to your specific question, it seems that Scala 2.9.2 handles in a (very) special way that specific case. Running a few more tests:
scala> ignore(3.asInstanceOf[String])
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stri
ng
at .<init>(<console>:9)
at .<clinit>(<console>)
scala> ignore({ println("test"); "aaa" })
test
res6: Int = 42
You can see that the argument is always being evaluated, save for your case. Scala 2.10 definitely has the most consistent behavior. However, this issue should not affect any developer upgrading to Scala 2.10; I can't see any case where obj.asInstanceOf[Nothing] is correct code.
Related
I got nipped by a production bug where I passed an impure 0-ary function to a class that mistakenly expected a a bare result type.
def impureFunc(): Future[Any] = ???
case class MyService(impureDependency: Future[Any] /* should have been () => Future[Any] */)
Effectively, this made MyService immediately invoke impureFunc and cache the first result for the lifetime of the program, which led to a very subtle bug.
Normally, the type system prevents these sort of bugs, but because of the ability to call 0-ary functions without an argument list, the compiler accepted this program.
Obviously, this is a "feature" of Scala, designed to make code look cleaner, but this was a bad gotcha. Is there any way to make this a compiler warning or a linting error? In other words, disapprove the "Empty application" type of implicit method conversion?
From the comments here, it appears this behavior was deprecated with a warning in 2.12 and should become an error in 2.13. So it seems the answer is to use -deprecation -Xfatal-warnings after upgrading.
val label = Try("here_a").getOrElse("here_b")
In the case where here_a is not found, this is not falling back to here_b. Why is the .getOrElse not functioning?
Thanks #jwvh. These values are sting files paths and thus the exception is the following Exception in thread "main" java.io.FileNotFoundException:
As per Andrew James Ramirez's comment I tried this but issue persists.
Try(throw new Exception("FAIL here_a")).getOrElse("here_b")
I have also tried
Try(throw new Exception("FileNotFoundException here_a")).getOrElse("here_b")
Edit
It seems I may have oversimplified this question for SO. Some more context. The string is actually a file path. Perhaps this is making a difference?
Effectively, a json file may be found in one of two possible locations. I thus wish to try the first location and if a java.io.FileNotFoundException is returned, fall back on the second location. This is what I presently have:
val input_file = Try(throw new Exception("FAIL location_a/file_a.json")).getOrElse("location_b/file_a.json")
Edit V2
I am embarrassed to say that I found the simple error. I am running this scala code on spark and I forgot to repackage in between testing. sbt package was all that was required. :-/
I think you misunderstood Try. and .getOrElse
Definition of Try :
The Try type represents a computation that may either result in an exception, or return a successfully computed value. It's similar to, but semantically different from the scala.util.Either type.
scala> Try("here_a")
res1: scala.util.Try[String] = Success(here_a)
scala> Try("here_a").get
res2: String = here_a
scala> Try(throw new Exception("FAIL here_a")).getOrElse("here_b")
res3: String = here_b
scala>
It only fails if you throw Exception. null is still a value.
Try() returns either a Success(x) or a Failure(e), where x is the successful value returned and e is the exception that was thrown. getOrElse() unwraps the Success or supplies a default value.
If you're not getting the "OrElse" then your code isn't throwing a catchable exception.
It works as you expect it should.
$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_40).
Type in expressions for evaluation. Or try :help.
scala> val label = Try(throw new RuntimeException("here_a")).getOrElse("here_b")
label: String = here_b
Please provide more context in your question if you feel this answer is insufficient.
I have seen the symbol
???
used in scala code, i however don't know if it's meant to be pseudo code or actual scala code, but my eclipse IDE for scala doesn't flag it and the eclipse worksheet actually evaluates it.
I haven't been able to find anything via google search.
Any help will be appreciated.
Thanks
Yes, this is a valid identifier.
Since Scala 2.10, there is a ??? method in Predef which simply throws a NotImplementedError.
def ??? : Nothing = throw new NotImplementedError
This is intended to be used for quickly sketching the skeleton of some code, leaving the implementations of methods for later, for example:
class Foo[A](a: A) {
def flatMap[B](f: A => Foo[B]): Foo[B] = ???
}
Because it has a type of Nothing (which is a subtype of every other type), it will type-check in place of any value, allowing you to compile the incomplete code without errors. It's often seen in exercises, where the solution needs to be written in place of ???.
To search for method names that are ASCII or unicode strings:
SO search: https://stackoverflow.com/search?q=[scala]+%22%3F%3F%3F%22
finds this thread Scala and Python's pass
scalex covers scala 2.9.1 and scalaz 6.0 http://scalex.org/?q=%3C%3A%3C
Simple question, I have a problem where using mapTo on the result of ask results in a compiler error along the lines of:
not found: value ClassTag
For example:
(job ? "Run").mapTo[Result]
^
I don't understand why it needs a ClassTag to do the cast? If I substitute a standard class from Predef like String as in (job ? "Run").mapTo[String] that compiles OK.
This happens when I define the class right above the line in question, as in:
class Result {}
(job ? "Run").mapTo[Result]
I still get the same problem.
Thanks, Jason.
I should also state that I'm using Scala 2.10.0 and Akka 2.1.0 (if that makes a difference).
This seems to be a particular problem with the Scala 2.10.0 version
After adding
import reflect.ClassTag
the implicitly used ClassTag parameter in mapTo should work.
Either that or updating to a newer Version of Akka/Scala (which should be prefered if possible).
When I was writing my recent answer I also tried to solve the problem in more "functional" way, but stuck with the following problem:
scala> "1".asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
but
scala> Some("1".asInstanceOf[Int])
res29: Some[Int] = Some(1)
and only
scala> res29.get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
It looks like the Some's argument is lazy evaluated, but I can't find any clue in the sources. The x parameter in the Some constructor is strict.
Why does Some together with asInstanceOf has such a strange behavior?
The constructor argument is not lazily evaluated. The moment you get the error is the moment when the REPL try to display the result, as an Int (unboxToInt). If you look further in the stack, you find scala_repl_result.
I believe the problem is that asInstanceOf[Int] does no check at all at runtime. I don't know whether it is according to spec (for value types) or a bug. The compiler is tricked into accepting that "1" is an Int (or boxed Int), pending a runtime check implied by asInstanceOf, but which will not happen.
As Option/Some are not specialized, at runtime there is only Some[Object]. So for the JVM, there is a call to a constructor new Some(Object o), which is accepted at code verification and at runtime. The toString (called by the REPL on the freshly built Some) is inside the generic code, where T is treated as Object too (or AnyRef), so it works, and Some(1) is displayed. On the other hand, every time there is an access to the value in the context where the compiler knows the type of the generic parameter, a cast is inserted in the code (+ unboxing in case of a value type). This is when it actually fails (here REPL does unboxing before displaying).
Edit This was in Scala 2.8.1. According to comment by #incrop above, this is now fixed.