Новое поведение в Scala 2.10
Вот два сеанса REPL (вдохновленные этим вопросом, хотя мой вопрос отличается):
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
и
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)
...
Единственное различие заключается в том, что первый - это Scala 2.9.2, а второй - 2.10.0.
Может ли кто-нибудь указать на изменения в 2.10, которые приводят к этому новому поведению?
Я знаю, что приведение к Nothing
- это глупое дело, и что ответ может быть "это все undefined поведение, поэтому просто прекратите это делать", но оно похоже на то, что может потенциально имеют последствия для обновителей, и я не помню, чтобы прибегать к обсуждению изменений, которые могли бы объяснить это.
Ответы
Ответ 1
Так как Scala рассматривает null
по-разному от случая None
для опции, даже значение null
Nothing
проблематично - должны быть ровно нулевые экземпляры Nothing
, а не один экземпляр которые могут или не могут сломаться в зависимости от того, как вы его используете.
Таким образом, я не вижу, как старое поведение - это всего лишь ошибка. В примечаниях к выпуску следует отметить, что он был исправлен, но полагаться на .asInstanceOf[Nothing]
, чтобы сделать что-либо, кроме того, чтобы выбросить исключение, достаточно противоречит типу, что я не думаю, что больше ничего не требуется. (На самом деле, я даже не думаю, что примечание к выпуску необходимо.)
Ответ 2
Это похоже на проблему только с консолью, а не с языком. Если вы запустите это небольшое приложение, которое вызывает тот же самый метод, scala 2.10 не имеет проблемы с ним.
object Test extends App {
override def main(args: Array[String]) {
println(takesString(null.asInstanceOf[Nothing]))
}
def takesString(a: String) = 42
}
Чтобы упростить свой пример сверху, вы можете просто ввести
null.asInstanceOf[Nothing]
и консоль даст вам ту же ошибку. Я предполагаю, что это имеет какое-то отношение к распечатке типа.
Обновление: Похоже, я случайно побежал против 2.9.2. Все еще не работает как script в 2.10 RC5, как указывает автор в комментарии.
Ответ 3
Я знаю, что вы не ожидаете ответа "это все undefined поведение, поэтому (...)", но когда вы добавляете "вещь, которая потенциально может иметь последствия для обновлений", я должен помнить (даже если это очевидно), что люди не могут полагаться или ожидать чего-либо из результата вещи, которая имеет поведение undefined, своим собственным определением.
В конкретном случае, о котором вы говорили, я не думаю, что это поведение undefined: оно должно вызывать исключение. Nothing
является подклассом Null
, а не наоборот - мое первое ожидание, без тестирования, состояло в том, что строка null.asInstanceOf[Nothing]
выбрала бы ClassCastException
, так как Null
не является Nothing
. Однако вы можете видеть, что Null
является специальным экземпляром (как в Java). Попробуйте запустить:
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>)
Я предполагаю, что это происходит потому, что внутри, obj.asInstanceOf[T]
вызывает obj.getClass()
, чтобы проверить приведение во время выполнения. Как вызов любого метода на Null
выдает a NullPointerException
, это исключение выдается перед ClassCastException
.
Возвращаясь к вашему конкретному вопросу, кажется, что Scala 2.9.2 обрабатывает особым образом особый случай. Выполнение еще нескольких тестов:
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
Вы можете видеть, что аргумент всегда оценивается, кроме вашего случая. Scala 2.10 определенно имеет наиболее последовательное поведение. Однако эта проблема не должна влиять на обновление разработчика до Scala 2.10; Я не вижу случая, когда obj.asInstanceOf[Nothing]
является правильным кодом.