Почему в .NET существует ноль? - PullRequest
35 голосов
/ 01 марта 2011

Почему значения могут быть нулевыми в .NET?Разве это лучше, чем иметь гарантию, что все будет иметь значение, и ничто не вызовет нулевое значение?

Кто-нибудь знает, как называется каждая из этих методологий?

В любом случае, я не очень разбираюсь вэто, но отсутствие значения для всего упрощает, с точки зрения простоты, то есть устраняет пустые проверки и позволяет писать более оптимизированные алгоритмы, которые не нужно разветвлять для проверок.

Каковы плюсы и минусы каждого стиля с точки зрения производительности, простоты, параллелизма, перспективности и т. Д.

Ответы [ 11 ]

37 голосов
/ 01 марта 2011

У нас есть Тони Хоар , пионер, который работал над Алголом, чтобы поблагодарить за это.Он скорее сожалеет об этом:

Я называю это своей ошибкой в ​​миллиард долларов.Это было изобретение нулевой ссылки в 1965 году. В то время я разрабатывал первую всеобъемлющую систему типов для ссылок на объектно-ориентированном языке (ALGOL W).Моя цель состояла в том, чтобы гарантировать, что любое использование ссылок должно быть абсолютно безопасным, с проверкой, выполняемой автоматически компилятором.Но я не мог удержаться от соблазна вставить нулевую ссылку просто потому, что это было так легко реализовать.Это привело к неисчислимым ошибкам, уязвимостям и сбоям системы, которые, вероятно, причинили миллиард долларов боли и ущерба за последние сорок лет..

24 голосов
/ 01 марта 2011

Несмотря на привлекательность мира без null, он представляет большие трудности для многих существующих шаблонов и конструкций.Например, рассмотрим следующие конструкции, которые потребовали бы серьезных изменений, если бы null не существовало

  1. Создание массива ссылочных типов ala: new object[42].В существующем мире CLR массивы будут заполнены null, что недопустимо.Здесь семантика массива должна немного измениться
  2. . default(T) полезно, только когда T является типом значения.Использование его в ссылочных типах или неограниченных обобщенных типах недопустимо
  3. Поля в структуре, являющиеся ссылочным типом, должны быть запрещены.Тип значения может быть инициализирован 0 сегодня в CLR, который удобно заполняет поля ссылочных типов с null.Это не было бы возможно в ненулевом мире, поэтому поля, типы которых являются ссылочными типами в структурах, должны быть запрещены

Ни одна из перечисленных проблем не является неразрешимой, но они приводят к изменениям, которые действительноВыясните, как разработчики склонны думать о кодировании.Лично я хотел бы, чтобы C # и .Net были разработаны с устранением нуля, но, к сожалению, это не так, и я полагаю, что проблемы, подобные вышеизложенным, имели какое-то отношение к этому.

9 голосов
/ 01 марта 2011

Это напоминает мне эпизод из серии «Соединения» Джеймса Бёрка, где монахи переписывали арабский на латиницу и впервые встретили нулевую цифру. Римская арифметика не имела представления для нуля, но арабская / арамейская арифметика имела. "Почему мы должны написать письмо, чтобы ничего не указывать?" утверждал католических монахов. «Если это ничего, мы должны ничего не писать!»

К счастью для современного общества, они потеряли аргумент и научились писать ноль цифр в своей математике. ;>

Ноль просто означает отсутствие объекта. Есть языки программирования, которые не имеют «ноль» как таковые, но у большинства из них все еще есть что-то, что представляет отсутствие легитимного объекта. Если вы выбрасываете «null» и заменяете его на что-то с именем «EmptyObject» или «NullNode», это все равно null только с другим именем.

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

Здесь мы углубляемся в экзистенциализм, но: если вы можете представлять присутствие чего-либо, то разве не существует фундаментальной необходимости уметь также представлять отсутствие этого?

6 голосов
/ 01 марта 2011

I предполагают , что они существуют null в .NET, потому что он (C #) следовал в шагах C ++ / Java (и только начал разветвляться в более поздних версиях) и VB / J ++ (который стал VB.NET/J#) уже имел представление о значениях «ничего», то есть .NET имеет null из-за того, что было , а не из-за того, что мог быть.

В некоторых языках нет понятия null - null может быть полностью заменено на тип, такой как Maybe - существует Something (объект) или Ничего (но это не null! Нет способа вывести «Ничто» из «Возможно»! )

В Scala с опцией:

val opt = Some("foo") // or perhaps, None
opt match {
   case Some(x) => x.toString() // x not null here, but only by code-contract, e.g. Some(null) would allow it.
   case _ => "nothing :(" // opt contained "Nothing"
}

Это делается с помощью языкового дизайна в Haskell (null невозможно ... вообще!) И с помощью библиотечной поддержки и осторожного использования , например, в Scala, как показано выше. (Scala поддерживает null - возможно, для взаимодействия Java / C # - но можно писать код Scala без использования этого факта, если только null не разрешено «просачиваться»).

Редактировать: См. Scala: Опция Pattern , Scala: Опция Cheat Cheet и SO: Использовать Maybe Введите в Haskell . В большинстве случаев разговор о «Возможно в Хаскеле» поднимает тему монад. Я не буду утверждать, что понимаю их, но вот ссылка вместе с использованием Maybe .

Удачного кодирования.

5 голосов
/ 01 марта 2011

Хорошо, теперь переходите к волшебному слову C # -without-null

class View
{
    Model model;        

    public View(Model model)
    {
        Console.WriteLine("my model : {0}, thing : {1}", this.model, this.model.thing);
        this.model = model;
    }
}

Что напечатано на консоли?

  • Ничто не исключение при доступе к неинициализированномуобъект брошен: хорошо, назовите это NullReferenceException, и это текущий мир.
  • Он не создается, пользователю необходимо указать значение при объявлении модели, см. последнюю точку маркера, поскольку она создает тот же результат.
  • Некоторое значение по умолчанию для модели и некоторое значение по умолчанию для этой вещи: Хорошо, раньше с помощью null у нас был, по крайней мере, способ узнать, является ли экземпляр правильным, теперь компилятор генерирует странные двойники, которые не содержат ничего, кромевсе еще недопустимы в качестве объектов модели ...
  • Что-то определенное типом объектов: лучше, если бы мы могли определить конкретное недопустимое состояние для каждого объекта, но теперь каждый объект, который может быть недействительным, должен независимо реализовывать это вместе сспособ идентифицировать это состояние вызывающей стороной ...

Так что в принципе для меня это, кажется, ничего не решаетЧтобы удалить нулевое состояние, так как, возможно, все равно необходимо управлять недопустимым состоянием ...

Ну что, каким будет значение интерфейса по умолчанию?Да, и абстрактный класс, что произойдет, если метод вызывается со значением по умолчанию, определенным в абстрактном классе, но вызывающим другой метод, который является абстрактным?.... .... зачем усложнять модель даром, это снова вопросы множественного наследования!

Одним из решений было бы полное изменение синтаксиса, чтобы перейти к полнофункциональному, гдеНулевой мир не выходит, только Maybes, когда вы хотите, чтобы они существовали ... Но это не язык, похожий на C, и мультипарадигма .Net будет потеряна.

Чего не хватает, так этораспространяющий нуль оператор, способный возвращать ноль в model.Thing, когда модель нулевая, например model.?.Thing


Да, и на всякий случай ответ на ваш вопрос:

  • Текущая библиотека классов развивалась после того, как разгром Microsoft-Java и C # был построен как «лучше-Java», поэтому изменение системы типов для удаления нулевых ссылок было бы большим изменением.Им уже удалось ввести типы значений и убрать ручную упаковку!
  • Поскольку введение типов значений показывает, что Microsoft много думает о скорости ... Тот факт, что значение по умолчанию для всех типов соответствует нулевой заливке, действительно важендля быстрой инициализации массива, например.В противном случае для инициализации массивов эталонных значений потребовалась бы особая угроза.
  • Без нулевого взаимодействия с C было бы невозможным, поэтому, по крайней мере, на уровне MSIL и в небезопасном блоке им нужно было бы выжить.
  • Microsoft хотела использовать каркас для удаления VB6 ++ Nothing, так как он вызывается в VB, радикально изменил бы язык, пользователям потребовались годы, чтобы переключиться с VB6 на VB.Net, такое изменение парадигмы могло бытьфатально для языка.
3 голосов
/ 01 марта 2011

Истерические изюминки.

Это похмелье от языков уровня C, где вы живете при явном манипулировании указателями.Современные декларативные языки (Mercury, Haskell, OCaml и т. Д.) Довольно счастливо обходятся без нулей.Там каждое значение должно быть явно сконструировано.Идея 'null' обрабатывается через типы 'option', которые имеют два значения: 'no' (соответствует null) и 'yes (x)' (соответствует non-null со значением x).Вы должны распаковать каждое значение параметра, чтобы решить, что делать, следовательно: нет ошибок ссылки на нулевой указатель.

Отсутствие нулевых значений в языке экономит вам столько горя, это действительно позор, что идея все еще сохраняетсяязыки высокого уровня.

3 голосов
/ 01 марта 2011

Ну, значения (переменные типа значения) могут быть только null, так как типы Nullable были введены в Fx2.

Но я полагаю, вы имеете в виду:

Почему ссылки могут быть null?

Это часть полезности ссылок. Рассмотрим Tree или LinkedList, они были бы невозможны (не могут завершиться) без null.

Вы можете придумать еще много примеров, но в основном существует null для моделирования концепции «необязательных» свойств / отношений.

2 голосов
/ 01 марта 2011

Я также не знаком с альтернативами, но я не вижу разницы между Object.Empty и null, кроме нуля, позволяющего вам узнать, что что-то не так, когда ваш код пытается получить доступ к объекту, тогда как Object.Emptyпозволяет продолжить обработку.Иногда вы хотите одно поведение, а иногда вы хотите другое.Для этого полезен отличительный ноль от пустого.

1 голос
/ 18 января 2014

null - это просто имя значения по умолчанию для ссылочного типа.Если бы null не было разрешено, то концепция «не имеет значения» не исчезла бы, вы бы просто представили ее по-другому.В дополнение к специальному имени, это значение по умолчанию также имеет специальную семантику в случае неправильного использования - т.е. если вы обрабатываете его как существующее значение, тогда как на самом деле его нет.

Если былинет null:

  1. Вам необходимо определить значения по умолчанию для ваших типов, которые будут использоваться, когда «нет значения».В качестве тривиального примера рассмотрим последний узел прямого односвязного списка.
  2. Вам потребуется определить семантику для операций, выполняемых со всеми этими значениями часового значения.
  3. Среда выполнения будет иметь дополнительныенакладные расходы на обработку дозорных значений.В современных виртуальных машинах, таких как те, что используются в .NET и Java, нет никаких накладных расходов для проверки на ноль перед большинством вызовов функций и разыменованием, потому что ЦП предоставляет особые способы обработки этого случая, а ЦП оптимизирован для случаев, когдассылки не являются нулевыми (например, прогноз ветвления).

В итоге:

  • Имя изменится, но концепция не изменится.
  • бремя определения и передачи значения и семантики по умолчанию для случаев, когда у вас «нет значения», ложится на разработчиков и документацию для разработчиков.
  • Выполнение кода на современных виртуальных машинах может столкнуться с раздуванием кода и значительным снижением производительности для многих алгоритмов.

Проблемы с null, описанные Тони Хоаром, обычно связаны с тем, что до современных виртуальных машин системы времени выполнения не имели почти такой же чистой обработки неправильно используемых значений null, как вы.иметь сегодня.Неправильное использование указателей / ссылок остается проблемой, но отслеживание проблемы при работе с .NET или Java, как правило, на намного проще, чем раньше, например, на C.

1 голос
/ 18 января 2014

Многие люди, вероятно, не могут обернуть голову вокруг кодирования без нулей, и если бы в C # не было нулей, я сомневаюсь, что это бы завоевало популярность в такой степени.хорошая альтернатива была бы, если вы хотите разрешить пустую ссылку, то ссылка должна быть явно обнуляемой, как с типами значений.

Например,

Person? person = SearchForPersonByFirstName("Steve");
if (person.HasValue)
{
    Console.WriteLine("Hi, " + person.Value.FullName);
}

К сожалению,когда вышел C # 1.0, не было понятия Nullable;это было добавлено в C # 2.0.Принуждение ссылок к значениям сломало бы старые программы.

...