Какой смысл в классе Option [T]? - PullRequest
82 голосов
/ 17 января 2010

Я не могу понять суть класса Option[T] в Scala. Я имею в виду, я не могу видеть никаких преимуществ None над null.

Например, рассмотрим код:

object Main{
  class Person(name: String, var age: int){
    def display = println(name+" "+age)
  }

  def getPerson1: Person = {
    // returns a Person instance or null
  }

  def getPerson2: Option[Person] = {
    // returns either Some[Person] or None
  }

  def main(argv: Array[String]): Unit = {
    val p = getPerson1
    if (p!=null) p.display

    getPerson2 match{
      case Some(person) => person.display
      case None => /* Do nothing */
    }
  }
}

Теперь предположим, что метод getPerson1 возвращает null, а затем вызов display в первой строке main обязательно завершится с NPE. Точно так же, если getPerson2 возвращает None, вызов display снова завершится ошибкой с некоторой похожей ошибкой.

Если это так, то почему Scala усложняет ситуацию, вводя новый упаковщик значений (Option[T]) вместо того, чтобы следовать простому подходу, используемому в Java?

UPDATE:

Я отредактировал свой код в соответствии с предложением @ Mitch . Я до сих пор не вижу каких-либо особых преимуществ Option[T]. Я должен проверить для исключительных null или None в обоих случаях. (

Если я правильно понял из @ ответа Михаила , единственное преимущество Option[T] заключается в том, что он явно сообщает программисту, что этот метод может вернуть None ? Это единственная причина такого выбора дизайна?

Ответы [ 18 ]

3 голосов
/ 17 января 2010

Добавление к 1001 * тизеру ответа Рэндалла , чтобы понять, почему потенциальное отсутствие значения представлено Option, требует понимания того, что Option делится со многими другими типами в Scala - в частности, моделированием типов. монады. Если один представляет отсутствие значения со значением null, то это различие отсутствия-присутствия не может участвовать в контрактах, совместно используемых другими монадическими типами.

Если вы не знаете, что такое монады, или если вы не замечаете, как они представлены в библиотеке Scala, вы не увидите, с чем играет Option, и не увидите, что вы пропускаем. Использование Option вместо нуля дает много преимуществ, которые заслуживают внимания даже при отсутствии какой-либо концепции монады (некоторые из них я обсуждаю в разделе «Стоимость опции / Некоторые против нуля» scala-user поток списка рассылки здесь ), но говорить об этом изоляция - это все равно, что говорить о типе итератора реализации конкретного связанного списка, задаться вопросом, зачем это нужно, и все же упустить более общий контейнер / итератор / алгоритм интерфейс. Здесь также работает более широкий интерфейс, и Option предоставляет модель присутствия и отсутствия этого интерфейса.

2 голосов
/ 17 января 2010

Я думаю, что ключ кроется в ответе Synesso: опция не в первую очередь полезна как громоздкий псевдоним для нуля, но как полноценный объект, который может помочь вам с логикой. *

Проблема с нулем в том, что это отсутствие объекта. У него нет методов, которые могли бы помочь вам справиться с этим (хотя, как разработчик языка, вы можете добавлять к своему языку все более длинные списки функций, которые эмулируют объект, если вы действительно этого хотите).

Одна вещь, которую Option может сделать, как вы продемонстрировали, это эмулировать null; Затем вы должны проверить необычное значение «None» вместо необычного значения «NULL». Если вы забудете, в любом случае произойдут плохие вещи. Опция делает его менее вероятным случайным образом, так как вы должны набрать «get» (что должно напомнить вам, что может быть null, я имею в виду None), но это небольшое преимущество в обмен на дополнительный объект-обертку.

Там, где Option действительно начинает показывать, что его сила помогает вам разобраться с концепцией «я хотел чего-то, но я не хочу на самом деле иметь».

Давайте рассмотрим некоторые вещи, которые вы, возможно, захотите сделать с вещами, которые могут быть нулевыми.

Может быть, вы хотите установить значение по умолчанию, если у вас есть ноль. Давайте сравним Java и Scala:

String s = (input==null) ? "(undefined)" : input;
val s = input getOrElse "(undefined)"

Вместо несколько громоздкой конструкции?: У нас есть метод, который имеет дело с идеей «использовать значение по умолчанию, если я нулевой». Это немного очищает ваш код.

Возможно, вы захотите создать новый объект, только если у вас есть реальная стоимость. Сравните:

File f = (filename==null) ? null : new File(filename);
val f = filename map (new File(_))

Scala немного короче и снова избегает источников ошибок. Затем рассмотрите кумулятивную выгоду, когда вам нужно объединить все вместе, как показано в примерах Синессо, Даниэля и парадигматика.

Это не значительное улучшение, но если вы все сложите, оно того стоит везде, за исключением очень высокопроизводительного кода (где вы хотите избежать даже крошечных накладных расходов на создание Some ( х) объект-обертка).

Использование совпадений на самом деле не так уж полезно, кроме как в качестве устройства, предупреждающего вас о нулевом / нулевом случае. Когда это действительно полезно, это когда вы начинаете цепочку, например, если у вас есть список опций:

val a = List(Some("Hi"),None,Some("Bye"));
a match {
  case List(Some(x),_*) => println("We started with " + x)
  case _ => println("Nothing to start with.")
}

Теперь вы можете сложить все случаи None и List-is-empty вместе в одно удобное утверждение, которое извлекает именно то значение, которое вы хотите.

1 голос
/ 30 июля 2010

Это действительно вопрос стиля программирования. Используя функциональную Java или написав собственные вспомогательные методы, вы можете использовать функциональность Option, но не отказаться от языка Java:

http://functionaljava.org/examples/#Option.bind

То, что Scala включает его по умолчанию, не делает его особенным. В этой библиотеке доступно большинство аспектов функциональных языков, и она может прекрасно сосуществовать с другим кодом Java. Так же, как вы можете программировать Scala с нулями, вы можете программировать Java без них.

1 голос
/ 17 января 2010

Нулевые возвращаемые значения присутствуют только для совместимости с Java. Вы не должны использовать их иначе.

0 голосов
/ 17 января 2010

Заранее признав, что это бойкий ответ, Option - это монада.

0 голосов
/ 18 декабря 2012

Другая ситуация, когда работает Option, - это ситуации, когда типы не могут иметь нулевое значение. Невозможно сохранить значение NULL в значениях типа Int, Float, Double и т. Д., Но с параметром можно использовать None.

В Java вам потребуется использовать коробочные версии (целое число, ...) этих типов.

0 голосов
/ 18 декабря 2012

Реальное преимущество наличия явных типов опций заключается в том, что вы можете , а не использовать их в 98% всех мест и, таким образом, статически исключать нулевые исключения. (А в остальных 2% система типов напоминает вам проверять правильность, когда вы на самом деле получаете к ним доступ.)

0 голосов
/ 18 января 2010

На самом деле я разделяю сомнения с вами. Что касается Option, меня действительно беспокоит то, что 1) производительность снижается, так как существует множество «некоторых» оболочек, созданных каждый раз. 2) Я должен использовать много Some и Option в моем коде.

Таким образом, чтобы увидеть преимущества и недостатки этого решения по проектированию языка, мы должны принять во внимание альтернативы. Поскольку Java просто игнорирует проблему обнуляемости, это не альтернатива. Фактическая альтернатива предоставляет язык программирования Fantom. Там есть обнуляемые и не обнуляемые типы и? ?: операторы вместо карты Scala / flatMap / getOrElse. В сравнении вижу следующие пули:

Преимущество опции:

  1. более простой язык - никаких дополнительных языковых конструкций не требуется
  2. униформа с другими монадическими типами

Преимущество Nullable:

  1. более короткий синтаксис в типичных случаях
  2. лучшая производительность (поскольку вам не нужно создавать новые объекты Option и лямбды для карты, flatMap)

Так что здесь нет очевидного победителя. И еще одна заметка. Нет принципиального синтаксического преимущества использования Option. Вы можете определить что-то вроде:

def nullableMap[T](value: T, f: T => T) = if (value == null) null else f(value)

Или используйте некоторые неявные преобразования для получения синтаксиса с точками.

...