Почему Scala позволяет передавать значение null?

#scala

Вопрос:

Я просматриваю книгу Scala.

Вот пример:

   def toInt(s: String): Option[Int] = {
    try {
      Some(Integer.parseInt(s.trim))
    } catch {
      case e: Exception => None
    }
  }

  val x = null
  println(toInt(x)) // < ---- why compiler does not complain about Null ?
 

toInt должно разрешаться только String в качестве аргумента, но компилятор согласен с null.

Почему? Такое поведение запрещено в Rust и TypeScript.

Есть ли какой-нибудь флаг или что-то еще ?

Комментарии:

1. Да, Котлин тоже все правильно понял. Несмотря на все то, что Scala проделала замечательную работу, оставить null без внимания, возможно, самое худшее решение в Scala. Похоже, Дотти может что-то сказать по этому поводу , чего бы это ни стоило

2. @SilvioMayolo Котлин, по крайней мере, попытался сделать это правильно, но довольно скоро обнаружил, что это легче сказать, чем сделать ; однако я не проверял, произошли ли какие-либо недавние изменения в этом направлении.

3. Может быть, также стоит объяснить, почему это отличается в TS и Rust. 1. У TS в качестве основы был JS, а у JS вообще не было системы типов. Таким образом, система типов TS была в основном проектом «зеленого поля», и у нее была возможность «сделать это правильно» с самого начала (что она и сделала, довольно успешно). Этого не было в случае с Java, в которой это уже было String включено null и т. Д. 2. Аналогично для Rust: is не должен был быть совместим с любыми токсичными аннотациями устаревшего типа, поэтому он поступил правильно и полностью исключил null концепцию.

4. Спасибо за объяснение @Андрей Тюкин

Ответ №1:

Option может помочь, потому что Option(null) == None

 def toInt(s: String): Option[Int] =
  Option(s).flatMap(_.toIntOption)

toInt(null) // None
 

но обычно мы предвосхищаем это такими подписями, как

 def toInt(s: Option[String]): Option[Int]
 

и оберните устаревшие API, которые могут возвращать значение null, слоем Scala

 toInt(Option(legacyJavaApi()))
 

Также линтеры, такие как Wartremover, могли бы помочь: https://www.wartremover.org/doc/warts.html#null

Иногда бывает полезен трюк var x: A = null.asInstanceOf[A] с инициализацией, где A находится параметр типа, потому что в противном случае чему бы вы назначили x ?.

Комментарии:

1. Есть null ли какой-то супертип для всех типов?

2. @капитан-йоссариан Это подтип любого другого ссылочного типа. Начиная с Scala 3, его можно изменить так, чтобы он был только подтипом Any с -Yexplicit-nulls флагом.