Почему "null" присутствует в C# и Java?

Мы заметили, что множество ошибок в нашем программном обеспечении, разработанном на C# (или Java), вызывают исключение NullReferenceException.

Есть ли причина, по которой "null" вообще был включен в язык?

В конце концов, если бы не было «null», у меня не было бы ошибки, верно?

Другими словами, какая функция языка не могла бы работать без null?

У меня возникло много ошибок, потому что что-то вызвало исключение, можем ли мы их также оставить ...

Omar Kooheji 07.10.2008 15:44

-5 голосов? Ну да ладно, хватит за идею, что этот сайт приветствует вопросы программирования любого уровня.

David Arno 07.10.2008 15:47

@ Cody Brocious: Сообщество явно полно довольно неприятных людей, которые наказывают тех, кто осмеливается задавать экстремальные вопросы новичкам. Ответ может быть очевиден для вас, но не будет очевиден для тех, кто только начинает программировать.

David Arno 07.10.2008 15:53

И это определенно вопрос не для новичков! Null - это пережиток сборки / C, а не существенная особенность!

bltxd 07.10.2008 15:57

Есть ли значок для большинства комментариев к вопросу? Потому что должно быть. Кроме того, во время «Иисус переворачивает птицу», говоря людям не грубить. Я люблю вас, ребята.

user1228 07.10.2008 16:03

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

Echostorm 07.10.2008 16:06

Я должен сказать, что редактирование Роба лучше. Теперь это почти разумный вопрос.

user1228 07.10.2008 16:12

Хм, кто-то отредактировал его и значительно прояснил.

user1228 07.10.2008 16:15

Как отмечалось ранее, все, что я сделал, это обновил теги, Rich B отредактировал вопрос заранее. По большей части это может быть вопрос вводного уровня, но я видел, как он появляется на некоторых вводных курсах, поэтому это не причина, по которой кто-то не может задать этот вопрос.

rjzii 07.10.2008 16:19

@ blue.tuxedo.myopenid.com: Не важная функция? Попробуйте запрограммировать базу данных без нее. Вам нужно будет обработать null, даже если вы просто собираетесь перевести его на что-то другое.

CodeRedick 07.10.2008 16:32

@Telos, вы запрашиваете возможность выбора, а не null, как показано в C#

bltxd 07.10.2008 17:37

Я не могу понять, как этот вопрос получил столько голосов.

Konrad Rudolph 09.10.2008 00:58

Он получил от меня +1, потому что я подумал, что это глупый вопрос, но, если подумать, это действительно интересная тема. Никогда даже не удосужился рассмотреть мир без «нуля».

Outlaw Programmer 28.01.2009 20:51
qconlondon.com/london-2009/presentation/… - Tony Hoare, inventor of NULL ( as a quick hack in Algol ), gave a talk on why it's a bad idea. If Turing award winning demi-gods can question it, why are people saying that the answer is obvious?
Pete Kirkham 19.08.2009 03:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
73
14
5 996
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

Я не могу говорить о вашей конкретной проблеме, но похоже, что проблема не в существовании null. Null существует в базах данных, вам нужно каким-то образом учесть это на уровне приложения. Я не думаю, что это единственная причина, по которой он существует в .net, заметьте. Но я думаю, это одна из причин.

-1. В .NET база данных NULL обычно представлена ​​как DBNull.Value вместо null.

stakx - no longer contributing 06.09.2010 00:07

Null - чрезвычайно мощная функция. Что делать, если у вас нет ценности? Это NULL!

Одна школа мысли - никогда не возвращать null, другая - всегда. Например, некоторые говорят, что вы должны вернуть действительный, но пустой объект.

Я предпочитаю null, поскольку для меня это более верное указание на то, что это на самом деле. Если я не могу получить объект со своего уровня сохраняемости, мне нужен null. Мне не нужно какое-то пустое значение. Но это я.

Это особенно удобно с примитивами. Например, если у меня есть true или false, но это используется в форме безопасности, где разрешение может быть Разрешено, Запрещено или не установлено. Ну, я хочу, чтобы это не было нулевым. Значит, я могу использовать bool?

Я мог бы рассказать гораздо больше, но я оставлю это здесь.

В ситуации Allow / Deny / NotSet вам нужно перечисление, а не то, что включает null.

Mark Cidade 07.10.2008 15:41

Ложь, Истина, FileNotFound. :-)

Chris Jester-Young 07.10.2008 15:48

Allow = True, Deny = False, Not Set = No Value, следовательно, NULL. Это был один простой пример. Да, Нет, Нет данных, Истина Ложь Не определено и т. д. Список можно продолжать и продолжать, он идеально подходит для значений типа bool с нулевым значением, а не для перечисления. Если бы у меня было Allow / Deny / IDontKNow / WhoCares / IAmHungry / NotSet, то я бы использовал enum.

mattlant 07.10.2008 18:53

Вы обнаружите, что null - это, возможно, наихудший способ встроить в данные элемент «без информации».

I GIVE CRAP ANSWERS 08.10.2008 23:24

Что, если в этом примере есть ошибка в коде, а программист просто забыл присвоить значение флагу Разрешить / Запретить? В этом случае значение null является ошибкой, оно не означает «НЕ УСТАНОВЛЕНА».

Outlaw Programmer 28.01.2009 20:55

Проголосовали против. Null - это на самом деле 2 концепции / функции: возможность представлять недопустимые состояния программы (бесполезно, imo), возможность представлять необязательность (обязательно). По сути, это не мощно, это глупо.

bltxd 28.10.2010 10:56

Null - важное требование любого объектно-ориентированного языка. Любая объектная переменная, которой не была назначена ссылка на объект, должна иметь значение NULL.

Итак, Никки, не могли бы вы объяснить этому невежественному старому дураку, что не так с моим утверждением?

David Arno 11.10.2009 23:01

@David: в основном нулевые ссылки не являются существенныйтребование любого языка OO. Одно решение: требовать инициализацию всего при объявлении / построении и использовать шаблон нулевого объекта для всего, что вам нужно, чтобы иметь нулевые / неопределенные / недопустимые / по умолчанию / пустые / любые значения.

R. Martinho Fernandes 08.12.2009 01:30

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

Как бы вы предложили убрать понятие ничтожности?

Это не принципиально. Вы можете потребовать инициализации любой переменной типа ref так же, как с типами значений (не допускающими значения NULL). Хотя это было бы хлопотно.

JacquesB 07.10.2008 16:26

Предположим, вам требуется инициализировать любую переменную типа ref. Предположим, что это статическое поле, и вы вызываете статический метод для инициализации поля - что, если этот метод смотрит на другое поле, которое еще не было инициализировано? Какую ценность это будет иметь?

Jon Skeet 07.10.2008 16:32

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

Jon Skeet 07.10.2008 16:32

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

Mark Cidade 07.10.2008 18:59

@marxidad: Ага, так что я могу понять функциональные языки без ноля. Я не думаю, что null можно удалить из C# без радикального изменения языка.

Jon Skeet 07.10.2008 19:04

Вы можете удалить null из подмножества типов, которые могут обрабатываться литералами (хотя все еще с трудностями), но на самом деле основным кандидатом на C#, строка просто окажется пустой строкой, а не null, что вряд ли станет большой победой. вариант расставить точки было бы неплохо, хотя

ShuggyCoUk 30.01.2009 02:46
@Jon: As I currently see it, you could declare a constant for any reference type, X.Exmpty (à la string.Empty or EventArgs.Empty), which would take the place of null references for that type. So I think C# could have potentially lived without null.
stakx - no longer contributing 06.09.2010 00:11

@stakx: Так что бы произошло, если бы вы попытались читать, например, из FileStream.Empty?

Jon Skeet 06.09.2010 01:27
@Jon: Unless one can think of something better to do, possibly an exception would be thrown. I didn't so much mean to say that you'd имеют to do things differently without null, but instead that nullможет be replaced by a type-specific default value. That by itself isn't much of an improvement, but demonstrates that nullмог be abolished. If you can then think of a more reasonable thing to return than throw an exception when reading from a hypothetical FileStream.Empty, который would be the real improvement!
stakx - no longer contributing 06.09.2010 23:15

@stakx: Похоже, они очень похожи на меня на очень. С таким же успехом вы можете просто разрешить вызов методов с нулевым значением this и реагировать соответствующим образом ... они в основном эквивалентны. (Фактически, может делает это в IL - вы можете вызвать метод экземпляра не виртуально с нулевым значением this.)

Jon Skeet 06.09.2010 23:33
@Jon, I remember you demonstrating the null this call (but can't remember where exactly?; +1 for that, anyway). Agreed that the two scenarios are almost identical. What null amounts to from this perspective is a convenience: You don't have to think twice about how you could handle the "no object" case more reasonably. FileStream.Emptyмощь or might not provide the nudge to find better solutions.
stakx - no longer contributing 06.09.2010 23:54

@Jon, под названием "недействительность" есть 2 понятия: неинициализированный и необязательный. Это то, что делает эту ошибку перенесенной из Алгола.

bltxd 28.10.2010 10:52

@Jon, неинициализированный не требуется, это похоже на запрос возможности отображать недопустимые состояния программы.

bltxd 28.10.2010 10:53

@Mark не могли бы вы уточнить? Боюсь, я не понимаю, как чисто функциональная идеология устраняет нулевой тип - вы никогда ничего не инициализируете?

sova 09.11.2010 09:36

Я думаю, что <code> null </code> полезен, но я согласен с stakx в том, что если бы был введен null (например, <code> String.null, Type.null </code>), некоторые из того, что затрудняет ошибки, связанные с null, исчезли бы сохраняя при этом одобрение программиста (поскольку отменить тип сложно по соглашению).

sova 09.11.2010 09:41

Если бы у меня были мои druthers, Nullable<T> был бы допустим для ссылочных типов, а ссылочные типы могли бы объявлять методы экземпляра в стиле не виртуальных вызовов требовать. Тогда вызов Length для нулевой строки может вернуть ноль, а не вызывать исключение с нулевой ссылкой (что делает значение по умолчанию для строкового типа допустимой пустой строкой).

supercat 01.05.2012 04:45

«Нулевой» включен в язык, потому что у нас есть типы значений и ссылочные типы. Вероятно, это побочный эффект, но я думаю, он хороший. Это дает нам большую власть над тем, как эффективно управлять памятью.

Почему у нас null? ...

Типы значений хранятся в «стеке», их значение находится непосредственно в этой части памяти (т.е. int x = 5 означает, что ячейка памяти для этой переменной содержит «5»).

С другой стороны, ссылочные типы имеют "указатель" в стеке, указывающий на значение действительный в куче (т.е. строка x = "ello" означает, что блок памяти в стеке содержит только адрес, указывающий на фактическое значение в куче. ).

Нулевое значение просто означает, что наше значение в стеке не указывает на какое-либо фактическое значение в куче - это пустой указатель.

Надеюсь, я объяснил это достаточно хорошо.

Проголосовали против. См. Типы опций на языках семейства ML. Короче говоря, делая ссылки непустыми, вы не теряете общности, вы просто делаете свои программы свободными от NullReferenceException.

bltxd 28.10.2010 10:33

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

Вы можете посмотреть на шаблон нулевого объекта, чтобы решить часть этой проблемы.

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

bltxd 28.10.2010 10:28

OCaml и Haskell полностью отличаются от C# и Java и основаны на разных идеях. Простое удаление null из C# или Java не сделает эти языки более похожими на чистый функциональный язык, такой как Haskell.

Mendelt 04.11.2010 21:09
Ответ принят как подходящий

Андерс Хейлсберг, «отец C#», только что рассказал об этом в его интервью Computerworld:

For example, in the type system we do not have separation between value and reference types and nullability of types. This may sound a little wonky or a little technical, but in C# reference types can be null, such as strings, but value types cannot be null. It sure would be nice to have had non-nullable reference types, so you could declare that ‘this string can never be null, and I want you compiler to check that I can never hit a null pointer here’.

50% of the bugs that people run into today, coding with C# in our platform, and the same is true of Java for that matter, are probably null reference exceptions. If we had had a stronger type system that would allow you to say that ‘this parameter may never be null, and you compiler please check that at every call, by doing static analysis of the code’. Then we could have stamped out classes of bugs.

Сайрус Наджмабади, бывший инженер-разработчик программного обеспечения в команде C# (теперь работающей в Google), обсуждает эту тему в своем блоге: (1-й, 2-й, 3-й, 4-й). Кажется, что самым большим препятствием для принятия типов, не допускающих значения NULL, является то, что нотация нарушит привычки программистов и базу кода. Примерно 70% ссылок на программы C#, скорее всего, завершатся как не допускающие значения NULL.

Если вы действительно хотите иметь ссылочный тип, не допускающий значения NULL, в C#, вам следует попробовать использовать Спецификация # которое является расширением C#, которое позволяет использовать "!" как знак, не допускающий значения NULL.

static string AcceptNotNullObject(object! s)
{
    return s.ToString();
}

Как ни странно, вчера вечером я писал о грязном взломе для реализации некоторых из этого: msmvps.com/blogs/jon_skeet/archive/2008/10/06/… Это действительно не хорошее решение, с различными подводными камнями, но тем не менее интересное (IMO!).

Jon Skeet 07.10.2008 16:56

На самом деле все типы должны быть неявными, не допускающими значения NULL, даже ссылочные типы. Обнуляемые типы (типы значений, а также ссылочные типы) должны быть явно отмечены знаком «?».

Michael Damatov 09.10.2008 11:06

Небольшая поправка: Сайрус Наджмабади больше не работает в команде C#. Я не осознавал этого, пока не получил от него внутреннее письмо сегодня, здесь, в Google :)

Jon Skeet 15.10.2008 14:01

Нулевой в C# в основном является переносом из C++, в котором были указатели, которые ни на что не указывали в памяти (или, скорее, на адрес 0x00). В это интервью Андерс Хейлсберг говорит, что он хотел бы добавить в C# ссылочные типы, не допускающие значения NULL.

Однако Null также имеет законное место в системе типов, как что-то вроде нижний тип (где object - это тип Вверх). В lisp нижний тип - NIL, а в Scala - Nothing.

Можно было бы разработать C# без каких-либо нулей, но тогда вам нужно было бы найти приемлемое решение для тех применений, которые обычно используются для null, например unitialized-value, not-found, default-value, undefined-value и None<T>. Вероятно, программисты на C++ и Java, вероятно, не приняли бы такого решения, если бы им это все-таки удалось. По крайней мере, до тех пор, пока они не увидят, что программы на C# никогда не имеют исключений с нулевым указателем.

Не говоря уже о том, что все, что вам действительно нужно сделать, это переименовать null.

CodeRedick 07.10.2008 16:34

Вам не нужно заменять ключевое слово "null" другим единственным ключевым словом. Вы можете ограничить значение «null», а затем добавить другие ключевые слова, которые будут означать разные вещи. Это может уменьшить количество ошибок нулевой ссылки. Даже в JavaScript есть «undefined» в дополнение к «null». VB6 имел "Пусто", "Ничего" И "Нулевое".

Mark Cidade 07.10.2008 18:56

Проголосовали против. Вы запутались между двумя способами использования null: «неинициализированный» бесполезен (цитируя jalf «бессмысленные состояния не должны быть представлены») и отличается от «необязательности», которая требуется.

bltxd 28.10.2010 10:35

@bltxd: ... что? Не могли бы вы уточнить

sova 09.11.2010 09:43

Меня просто удивляет, что некоторые люди (см. Телос выше) все еще путают None и Null. Я в основном не согласен со вторым абзацем: Null НЕТ законного места в современной системе типов. Null - это единственное значение, совместимое со всеми ссылочными типами, None <T> - нет, поскольку оно параметрическое. Это огромная разница. Голос против может быть немного резким, но плакат, кажется, подразумевает, что некоторые люди используют «неинициализированное значение», что неверно.

bltxd 09.11.2010 10:16

Если вы создаете объект с переменной экземпляра, являющейся ссылкой на какой-либо объект, какое значение вы бы предложили для этой переменной, прежде чем назначать ей какую-либо ссылку на объект?

Вариантов много. Например, компилятор может запретить использование переменных до того, как они будут явно инициализированы. Или компилятор может использовать конструктор по умолчанию (без параметров) и выдать ошибку, если такой конструктор не найден (например, в C++)

Niki 01.10.2009 18:22

Бывают ситуации, когда нулевой - хороший способ обозначить, что ссылка не была инициализирована. Это важно в некоторых сценариях.

Например:

MyResource resource;
try
{
  resource = new MyResource();
  //
  // Do some work
  //
}
finally
{
  if (resource != null)
    resource.Close();
}

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

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

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

В качестве примечания, Андерс Хейлсберг упомянул отсутствие принудительного применения ненулевого значения как одну из самых больших ошибок в спецификации C# 1.0, и что теперь включить ее «сложно».

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

Null в том виде, в каком он доступен в C# / C++ / Java / Ruby, лучше всего рассматривать как причуду какого-то неясного прошлого (Algol), которое каким-то образом сохранилось до наших дней.

Вы можете использовать его двумя способами:

  • Объявлять ссылки без их инициализации (плохо).
  • Обозначить необязательность (ОК).

Как вы уже догадались, 1) это то, что вызывает у нас бесконечные проблемы в общих императивных языках и должно было быть запрещено давно, 2) это действительно существенная особенность.

Существуют языки, которые избегают 1), но не препятствуют 2).

Например, таким языком является OCaml.

Простая функция, возвращающая постоянно увеличивающееся целое число, начиная с 1:

let counter = ref 0;;
let next_counter_value () = (counter := !counter + 1; !counter);;

Что касается опциональности:

type distributed_computation_result = NotYetAvailable | Result of float;;
let print_result r = match r with
    | Result(f) -> Printf.printf "result is %f\n" f
    | NotYetAvailable -> Printf.printf "result not yet available\n";;

1 это плохо? Вы говорите, всегда? Как насчет обработки исключений, когда вы хотите увидеть значение переменной в блоке catch? В значительной степени необходимо объявить его вне попытки и инициализировать его внутри, если инициализация может вызвать исключение!

CodeRedick 07.10.2008 16:39

Если ваша конструкция переменной не удалась, ее значение равно нулю.

bltxd 07.10.2008 16:51

По крайней мере, в Java вы должны объявлять ссылки без их инициализации: непримитивные поля классов (инициализированные в конструкторе), объекты, которые генерируют исключение во время создания, которое вам нужно использовать вне соответствующего блока try / catch и т. д.

PhiLho 07.10.2008 17:14

@ blue - И если бы не было "нулевого" значения, не было бы никакого способа указать на сбой, не так ли? Потому что без нулевого значения переменная была бы мусором, и не всегда можно отличить ненулевое значение мусора от хорошего значения.

Onorio Catenacci 07.10.2008 17:16

@PhiLho: объект, который вызвал исключение во время создания, никогда не создается. Конечно, чтобы использовать его впоследствии, вы должны использовать null, но вы также можете отслеживать его успешную инициализацию с помощью логического значения. По сути, ваша логика не требует null, но использует его.

bltxd 07.10.2008 18:21

@Onorio: Другое дело - обработка ошибок, и OCaml предоставляет (быстрые) исключения.

bltxd 07.10.2008 18:22

Вы слишком упрощаете. Конечно, это могло произойти при инициализации ИЛИ на следующем операторе, и в этом случае переменная будет иметь значимую информацию. Если вы действительно не хотите иметь try / catch для каждой строки кода, вы будете объявлять несколько неинициализированных переменных для использования в catch.

CodeRedick 07.10.2008 19:22

@Telos: Я бы не стал упрощать, если бы привязки базы данных для OCaml не были полностью реализованы и работоспособны. Скептицизм - это нормально, но попробуйте, и вы убедитесь в этом сами. Язык работает по-другому, и неудивительно, что код, который вам придется писать, также будет другим.

bltxd 08.10.2008 13:12

@Telos: взгляните на F# (порт Microsoft OCaml на .NET), а точнее на research.microsoft.com/fsharp/manual/spec2.aspx#_Toc20778559‌ 5. На этой странице подробно описывается причина, по которой им пришлось ввести null в F#: технические ограничения в .NET и совместимость с существующими API.

bltxd 08.10.2008 13:26

@Telos: У них не было выбора, поскольку они не могли обновить свои устаревшие API и внутреннее устройство. Итак, что мы должны сделать вывод?

bltxd 08.10.2008 13:31

@Telos: Удаление null невозможно при жизни в мире C? Все существующие привязки OCaml для библиотек C доказывают обратное.

bltxd 08.10.2008 13:32

Если вы получаете исключение NullReferenceException, возможно, вы продолжаете ссылаться на объекты, которые больше не существуют. Это не проблема с "null", это проблема с вашим кодом, указывающим на несуществующие адреса.

Я удивлен, что никто не сказал в ответ о базах данных. В базах данных есть поля, допускающие значение NULL, и любой язык, который будет получать данные из БД, должен это обрабатывать. Это означает наличие нулевого значения.

Фактически, это настолько важно, что для базовых типов, таких как int, вы можете сделать их допускающими значение NULL!

Также рассмотрите возвращаемые значения из функций, что, если бы вы хотели, чтобы функция делила пару чисел, а знаменатель мог бы быть 0? Единственный «правильный» ответ в таком случае будет нулевым. (Я знаю, что в таком простом примере исключение, вероятно, было бы лучшим вариантом ... но могут быть ситуации, когда все значения верны, но действительные данные могут дать неверный или неисчислимый ответ. Не уверен, что в таком случаи...)

Обработка материалов БД означает наличие нулевого значения. Большая разница в том, что в C# у вас NULL использованная литература. Пример разделения, в котором вы не генерируете исключение, уже существует (арифметика с плавающей запятой IEEE 754) и доказывает, что «единственный» правильный ответ - это не пустые ссылки. IEEE 754 использует нулевое значение ценить (NaN - не число).

R. Martinho Fernandes 08.12.2009 01:40

В одном из ответов упоминалось, что в базах данных есть нули. Это правда, но они сильно отличаются от нулей в C#.

В C# нули - это маркеры для ссылки, которая ни на что не ссылается.

В базах данных пустые значения - это маркеры для ячеек значений, которые не содержат значения. Под ячейками значений я обычно подразумеваю пересечение строки и столбца в таблице, но концепция ячеек значений может быть расширена за пределы таблиц.

На первый взгляд разница между ними кажется тривиальной. Но это не так.

+1 для указания разницы между нулевым использованная литература и значения, что означает, что что-то является нулевым / недействительным / по умолчанию / пустым / чем угодно.

R. Martinho Fernandes 08.12.2009 01:41

After all, if there were no "null", I would have no bug, right?

Ответ - НЕТ. Проблема не в том, что C# допускает null, проблема в том, что у вас есть ошибки, которые проявляются с помощью NullReferenceException. Как уже было сказано, нули имеют цель в языке обозначать либо «пустой» ссылочный тип, либо не-значение (пусто / ничего / неизвестно).

Удаление null из языка уменьшит вероятность определенных классов ошибок точно так же, как удаление типов указателей снижает вероятность определенных классов ошибок. Если вам действительно нужен null, вы можете использовать небезопасный блок. Типы значений существуют нормально и не допускают значения NULL.

Mark Cidade 07.10.2008 19:03

Суть pro3carp3 заключается в том, что большинство нулевых ошибок связано с использованием неинициализированных переменных, как если бы они были подготовлены к использованию. Типы, не допускающие значения NULL, на самом деле решают только случай «Мне все равно, какое значение, я просто хочу запустить этот метод», хотя обычно вам все равно.

Guvante 08.10.2008 23:15

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

bltxd 28.10.2010 10:45

bltxd: Ваш комментарий представляет собой наивную точку зрения. Неверные состояния программы действительно возникают по причинам, не зависящим от программистов, таким как ошибки файловой системы, проблемы с подключением к Интернету и т. д. В таких ситуациях действительно имеет смысл использовать значения NULL. Это также бесценно для представления неизвестных, недопустимых и пустых полей базы данных.

pro3carp3 10.11.2010 07:31

Пожалуйста, ознакомьтесь с привязками OCaml или Haskell для PostgreSQL. Они управляют всем, что вы говорите, без повсеместной нулевой ссылки. Короче говоря, существующая практика доказывает, что вы ошибались.

bltxd 13.11.2010 04:38

Это хороший момент, инициализированные, но недопустимые объекты просто замаскируют проблемы, а значение null вызовет немедленный сбой.

user159335 30.11.2011 19:21

Null не вызывает исключений NullPointerExceptions ...

Программисты вызывают исключения NullPointerExceptions.

Без нулей мы возвращаемся к использованию фактического произвольного значения, чтобы определить, что возвращаемое значение функции или метода было недопустимым. Вам все равно нужно проверять возвращаемое -1 (или что-то еще), удаление нулей не решит волшебным образом лени, а лишь слегка запутает ее.

Проголосовали против. Попробуйте любой язык из семейства машинного обучения и получите просветление.

bltxd 28.10.2010 10:46

только что заметил отрицательный голос ... хотя он, как правило, упускает из виду суть вопроса, поскольку он был специально нацелен на C# и java. Тем не менее, я проверю их, не хочу упустить ключ к раю!

Newtopian 25.06.2014 04:06

Я предлагаю:

  1. Ban Null
  2. Расширить логические значения: True, False и FileNotFound

К сожалению, я не думаю, что большинство людей поймет шутку.

rjzii 07.10.2008 20:43

Обычно - NullReferenceException означает, что какому-то методу не понравилось то, что ему было передано, и он вернул пустую ссылку, которая позже использовалась без проверки ссылки перед использованием.

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

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

Помимо ВСЕХ уже упомянутых причин, NULL необходим, когда вам нужен заполнитель для еще не созданного объекта. Например. если у вас есть круговая ссылка между парой объектов, вам понадобится null, поскольку вы не можете создать оба экземпляра одновременно.

class A {
  B fieldb;
}

class B {
  A fielda;
}

A a = new A() // a.fieldb is null
B b = new B() { fielda = a } // b.fielda isnt
a.fieldb = b // now it isnt null anymore

Обновлено: вы можете вытащить язык, который работает без нулей, но это определенно не будет объектно-ориентированным языком. Например, пролог не имеет нулевых значений.

Выберите существующий объектно-ориентированный язык, например C#. Теперь требуется инициализация всего при объявлении / построении и использовать шаблон нулевого объекта для всего, что вам нужно, чтобы иметь нулевые / неопределенные / недопустимые / по умолчанию / пустые / любые значения.

R. Martinho Fernandes 08.12.2009 01:31

Вопрос можно интерпретировать как «Лучше иметь значение по умолчанию для каждого типа ссылки (например, String.Empty) или null?». В этом предположении я бы предпочел иметь нули, потому что;

  • Я бы не хотел писать дефолт конструктор для каждого класса, который я пишу.
  • Я бы не хотел лишнего память для таких значения по умолчанию.
  • Проверка наличия ссылка нулевая, гораздо дешевле чем сравнение значений.
  • Это очень возможно иметь больше ошибок, которые труднее обнаружить, вместо NullReferanceExceptions. Это хорошо иметь такое исключение что ясно указывает на то, что я делать (предполагать) что-то не так.

Как и многие вещи в объектно-ориентированном программировании, все восходит к АЛГОЛу. Тони Хоар назвал это своей «ошибкой на миллиард долларов». Во всяком случае, это преуменьшение.

Вот действительно интересный тезис о том, как сделать обнуление не значением по умолчанию в Java. Параллели с C# очевидны.

Котлин нулевой безопасен. Это скорее выбор языка дизайна, который заставляет вас убедиться, что ваши ссылки (или ptrs) на что-то ссылаются.

Anis LOUNIS 03.02.2017 08:44
  • Явное обнуление, хотя это бывает редко. Возможно, это можно рассматривать как форму защитного программирования.
  • Используйте его (или структуру, допускающую значение NULL (T) для значений, не допускающих значения NULL) в качестве флага, чтобы указать отсутствующее поле при сопоставлении полей из одного источника данных (поток байтов, таблица базы данных) объекту. Создание логического флага для каждого возможного поля, допускающего значение NULL, может стать очень громоздким, и может оказаться невозможным использовать контрольные значения, такие как -1 или 0, когда все значения в диапазоне этого поля допустимы. Это особенно удобно, когда полей очень много.

Являются ли они случаями использования или злоупотребления - это субъективно, но я иногда их использую.

Если фреймворк позволяет создавать массив некоторого типа без указания, что следует делать с новыми элементами, этот тип должен иметь какое-то значение по умолчанию. Для типов, которые реализуют семантику изменяемых ссылок (*), в общем случае нет разумного значения по умолчанию. Я считаю слабым местом платформы .NET отсутствие возможности указать, что вызов невиртуальной функции должен подавлять любую проверку на null. Это позволит неизменным типам, таким как String, вести себя как типы значений, возвращая разумные значения для таких свойств, как Length.

(*) Обратите внимание, что в VB.NET и C# семантика изменяемых ссылок может быть реализована либо классом, либо типом структуры; Тип структуры будет реализовывать семантику изменяемых ссылок, действуя как прокси для обернутого экземпляра объекта класса, на который он содержит неизменяемую ссылку.

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

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

Извините за то, что ответил с опозданием на четыре года, я удивлен, что ни один из ответов до сих пор не ответил на исходный вопрос таким образом:

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


  • Низкоуровневый вид

Сначала немного истории. Причина, по которой был изобретен null, - это эффективность. При низкоуровневом программировании на ассемблере нет абстракции, у вас есть значения в регистрах, и вы хотите максимально использовать их. Определение нуля как значения недействительный указатель - отличная стратегия для представления либо предмет, либо ничего.

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

  • Общий вид.

Семантически null не является необходимым для языков программирования. Например, в классических функциональных языках, таких как Haskell или в семействе ML, нет null, а есть типы с именем Maybe или Option. Они представляют собой более высокоуровневую концепцию необязательное значение, никоим образом не заботясь о том, как будет выглядеть сгенерированный код сборки (это будет работа компилятора).

И это тоже очень полезно, потому что позволяет компилятору использовать поймать больше ошибок, а это означает меньше исключений NullReferenceExceptions.

  • Объединяя их

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

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

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

Функция, которая не может работать без нуля, - это возможность представить «отсутствие объекта».

Отсутствие объекта - важное понятие. В объектно-ориентированном программировании он нужен нам для представления ассоциации между объектами, которая является необязательной: объект A может быть присоединен к объекту B, или A может не иметь объекта B. Без нуля мы все равно могли бы эмулировать это: например, мы могли бы использовать список объектов, чтобы связать B с A. Этот список может содержать один элемент (один B) или быть пустым. Это несколько неудобно и на самом деле ничего не решает. Код, который предполагает, что существует B, например aobj.blist.first().method(), взорвется аналогично исключению с нулевой ссылкой: (если blist пуст, каково поведение blist.first()?)

Говоря о списках, null позволяет завершить связанный список. ListNode может содержать ссылку на другой ListNode, которая может иметь значение NULL. То же самое можно сказать и о других структурах динамического набора, таких как деревья. Null позволяет вам иметь обычное двоичное дерево, конечные узлы которого помечены имеющими дочерние ссылки, которые имеют значение NULL.

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

Проблемы, связанные с нулевыми ссылками, такими как пустые ссылки, случайно возникающие из-за ошибок и вызывающие исключения, частично являются следствием системы статических типов, которая вводит нулевое значение в каждый тип: есть пустая строка, нулевое целое число, нулевой виджет, ...

В динамически типизированном языке может быть один нулевой объект, который имеет свой собственный тип. В результате у вас есть все репрезентативные преимущества null плюс большая безопасность. Например, если вы пишете метод, который принимает параметр String, то вам гарантируется, что параметр будет строковым объектом, а не null. В классе String нет нулевой ссылки: то, что известно как String, не может быть нулевым объектом. Ссылки не имеют типа на динамическом языке. Место хранения, такое как член класса или параметр функции, содержит значение, которое может быть ссылкой на объект. Этот объект имеет тип, а не ссылку.

Таким образом, эти языки предоставляют чистую, более или менее математически чистую модель «нуля», а затем статические языки превращают ее в своего рода монстра Франкенштейна.

Другие вопросы по теме