36

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

Есть ли у вас какие-либо мысли, особенно за или против null? Вы когда-нибудь создавали функциональность, которая требовала нулевого значения?

+0

Благодарим за понимание, Патрик. – Allyn

+0

Возможный дубликат http://stackoverflow.com/questions/178026/why-is-null-present-in-c-sharp-and-java – nawfal

ответ

41

Null: The Billion Dollar Mistake. Тони Хоар:

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

+0

Это зависит от того, как будет использоваться ваш язык. Я не могу представить себе С без него. –

+1

Было бы неплохо, если бы они придумали какой-то не нулевой идентификатор. В C# они недавно добавили типы с нулевым значением, которые вы можете объявить как MyType? ... было бы неплохо, если бы вы могли определить параметры метода, чтобы никогда не быть нулевым ... т.е. что-то вроде MyType! или что-то еще ... – mezoid

+0

Я всегда был поклонником шаблона нулевого объекта. – moffdub

1

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

Если вы создаете динамически типизированный язык, NULL может пригодиться, поскольку это просто еще один «тип» без каких-либо изменений.

5

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

+3

Связанный список может быть построен следующим образом: Node-> Node-> Node-> EndNode На самом деле, как списки строятся на языках, которые не имеют значений «null». –

12

Обычно я думаю об «нулевом» в аспекте C/C++ «адрес памяти 0». Это не строго необходимо, но если бы этого не было, тогда люди просто использовали бы что-то другое (если myNumber == -1 или myString == "").

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

В .NET-мире MS недавно добавила типы с нулевым значением для int, long и т. Д., Которые никогда не имели значения NULL, поэтому я думаю, они думают, что это тоже очень важно.

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

+0

Я бы тоже его сохранил. Я имею в виду, что еще вы бы назначили для ссылки, которая ничего не значит? (обратите внимание на каламбур) –

+0

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

+0

Brenton: Итак, как бы вы реализовали обратный вызов из класса? Вы должны сохранить указатель на функцию обратного вызова в классе, но какое значение было бы, если бы вы вызывали setCallback()? – Timmmm

3

Вы можете думать о любом типе как о наборе вместе с набором операций. Есть много случаев, когда удобно иметь значение с не является «нормальным» значением; например, рассмотреть значение «EOF». для C's getline(). Вы можете обработать это одним из нескольких способов: у вас может быть значение NULL вне набора, вы можете отличить конкретное значение как null (в C, ((void *)0) может служить этой цели) или вы можете создать способ создания нового типа, так что для типа T, вы создаете тип = Защита {T ∪ NULL}, который является способом Haskell делает это (а„Может быть“тип).

Какой из них лучше подходит для многих приятных аргументов.

3

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

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

CLARIFICATION Основано на комментариях: Я ненавижу defacto null значение указателя нуля хуже, чем я ненавижу null.

Каждый раз, когда я вижу назначение обнулить, я думаю, «О, хорошо, кто-то просто поставить мину в коде. Когда-нибудь, мы будем ходить вниз связанный путь выполнения и БУМ! NullPointerException !»

Что я хотел бы, чтобы кто-то указал полезный по умолчанию или NullObject, который позволяет мне знать, что «этот параметр не был настроен ни на что полезное». Лысый нуль сам по себе - это просто неприятность, ожидающая своего служения.

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

+0

Не лучше ли получить и «исключить NullPointerException» вместо того, чтобы указывать на то, что похоже на правовые ценности, но на самом деле это не так? – simon

+1

Как сказал Симон, исключение NullPointerException является аргументом * для * null, а не против него. – phihag

+0

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

3

Null не является ошибкой. Null означает, что «я не знаю, пока»

Для примитивов вы на самом деле не нужен нуль (я должен сказать, что строки (в .NET) не должны получить его ИМХО)

Но для которые, безусловно, служат цели.

+0

Я не согласен - без нулевых примитивов вы часто оказываетесь в отключении между системами, которые обрабатывают что-либо как nullable, а ваши непустые примитивы заканчиваются булевыми флагами, чтобы указать, что это число означает что-то против нет, на самом деле это не так. Или вы получаете специальные значения дозорного. –

+0

Да, но для чего нужен System.Nullable <>. Это в основном автоматическая реализация булевского флага. –

28

null - значение дозорного, которое не является целым числом, а не строкой, а не булевым - не что-то действительно, кроме того, что нужно удерживать и быть значением «не существует». Не рассматривайте его как ожидаемое значение 0 или пустую строку или пустой список. Это все допустимые значения и могут быть гениально достоверными значениями во многих случаях - идея нулевого значения означает, что там есть no.

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

+0

Хороший ответ, чтобы не полагаться на значение, равное нулю, потому что это не обязательно. Вы могли бы добавить, что исторически для производительности компиляторы часто используют значение 0 как значение нулевого указателя, потому что тестирование против 0 (или не 0) обычно является одной машинной инструкцией. –

+0

«Не приравнивайте его к 0 или пустой строке или пустой список». Но также не уделяйте слишком много внимания тому, чтобы они были разными. Хотя вы, возможно, технически правы, избегая тонких и запутывающих деталей, это безопаснее. Мне нравится, как Oracle обрабатывает пустые строки как null. – Thilo

+1

Я предпочитаю null и "" быть отличным. Если я проверяю значение null, я обычно не хочу, чтобы «" совпадали. То, что Oracle gotcha опасно. – staticsan

3

Null полезен в ситуациях, когда существуют переменные с неназначенными значениями. Если каждая переменная имеет значение, то нет необходимости в нулевых значениях.

+0

Ваше утверждение верно только тогда и только тогда, когда всем переменным может быть присвоено значение. Никаких специальных значений (ака часовых) тоже нет. Математики уже давно вышли за рамки натуральных чисел. bool isCompliant (yes/no) или Nullable isCompliant (да/нет/неизвестно). Нульы более точно моделируют реальную жизнь. –

7

понятие null не является строго необходимым в том же смысле, что понятие нуля не является строго необходимым.

+1

Null - это личность того, что происходит, точно? –

+0

@ [Норман Рэмси]: вопрос предполагает недопустимое предположение. Null не является элементом в серии, это дозорный, означающий «нет значения». –

+0

@Norman: Хотя я согласен с тем, что 'null' не так фундаментален, как ноль, на многих языках есть оператор, для которого' null' является элементом идентификации: http://en.wikipedia.org/wiki/Null_coalescing_operator –

25

О нет, я чувствую, что философия главным выходит из меня ....

Понятие NULL происходит от понятия пустого множества в теории множеств. Почти все согласны с тем, что пустое множество не равно нулю. Математики и философы боролись о ценности теории множеств на протяжении десятилетий.

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

С уважением, Sam

+1

Это кажется лучший ответ на вопрос, разрешать ли пустые списки, кроме того, нужно ли иметь нулевое значение. – recursive

+0

Действительно, без нулевого значения более булевых флагов следует использовать, чтобы указать, что «значение, которое было установлено на ноль, фактически не является значением вообще». – Arafangion

+1

У вас в философии была философия? Как, черт возьми, это дошло !? – Rob

3

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

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

Кроме того, нулевой символ в строке переменной длины C-стиля используется для обозначения конца строки.

Использование null этими способами, особенно для значений указателей, стало настолько популярным, что метафора была импортирована в другие системы, даже если значение «нулевой» дозорное реализовано совершенно по-другому и не имеет никакого отношения к числу 0.

5

В C NULL было (void * (0)), поэтому это был тип со значением (?). Но это не сработало с C++-шаблонами, поэтому C++ сделал NULL 0, он сбросил тип и стал чистым значением.

Однако было обнаружено, что наличие определенного типа NULL будет лучше, поэтому они (комитет C++) решили, что NULL снова станет типом (в C++ 0x).

Кроме того, почти каждый язык, кроме C++, имеет NULL как тип или эквивалентное уникальное значение, не то же самое, что и 0 (он может быть равен ему или нет, но его не то же значение).

Так что теперь даже C++ будет использовать NULL в качестве типа, в основном закрывании дискуссии по этому вопросу, так как теперь все (почти) будет иметь тип NULL

Edit: Думая об этом в Haskell может быть другое решение к типам NULL, но его не так легко понять или реализовать.

0

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

Вначале может показаться очевидным, что это означает «нет значения», но то, что НАСТОЯТЕЛЬНО означает, зависит от контекста. Если, например, LastName === null, означает ли это, что у человека нет фамилии или что мы не знаем, что такое их фамилия, или что он еще не введен в систему? Нулевое значение равно или не так ли? В SQL это не так. На многих языках это происходит. Но если мы не знаем значения personA.lastName или personB.lastName, как мы можем узнать, что personA.lastName === personB.lastName, а? Если результат будет ложным или .... ноль?

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

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

+0

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

+0

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

+0

Нет, конечно нет. По крайней мере, когда вы получаете исключение нулевого указателя или segfault, это болезненное напоминание о том, что вы делаете что-то неправильно. Выполнение backflip для отключения исключения не означает, что вы еще не делаете что-то неправильно. – Breton

0

Null - это объекты, которые 0 являются числами.

+1

Неправильно. Null представляет «Nothing», а 0 - действительное значение «Not Nothing». – Craig

+1

Я всегда понимал это как «отсутствие ценности» a la Stand и Deliver. Я никоим образом не говорю, что null == 0, я говорю, что в домене чисел, когда у вас нет значения, он представлен нулем. В домене объектов отсутствие значения равно null. Наверное, я пытался быть слишком смелым;) – TJB

+1

@ Крейг - кроме случаев, когда вы его разделяете. –

2

Это решение зависит от цели программирования языка.

Для кого вы разрабатываете язык программирования? Вы разрабатываете его для людей, знакомых с c-производными языками? Если это так, то вам, вероятно, следует добавить поддержку null.

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

Возьмите блоки переключателей в C# в качестве примера. Все метки меток на C# должны иметь явное выражение потока управления в каждой ветви. То есть все они должны заканчиваться либо выражением «break», либо явным goto. Это означает, что в то время как этот код является законным:

switch(x) 
{ 
    case 1: 
    case 2: 
     foo; 
     break; 
} 

, что этот код не был бы законным:

switch (x) 
{ 
    case 1: 
     foo(); 
    case 2: 
     bar(); 
     break; 
} 

Для того, чтобы создать «проваливаться» от случая 1 к случаю 2, то необходимо вставить Гото, например:

switch (x) 
{ 
    case 1: 
     foo(); 
     goto case 2; 
    case 2: 
     bar(); 
     break; 
} 

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

Если ваша цель - создать язык, ориентированный на программистов на С ++, то удаление null, вероятно, нарушит их ожидания. Это вызовет путаницу и затруднит изучение вашего языка. Ключевой вопрос заключается в том, «какую пользу они получают»? Или, альтернативно, «какой ущерб причиняет это».

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

Итак, повторим, я бы сказал, что вы должны:

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

Обычно это сделает желаемый результат довольно ясным.

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

7

Я не думаю, что полезно говорить об отсутствии вне контекста всего дизайна языка. Первая точка путаницы: пустой пуст, или он включает в себя одно выделенное значение (часто называемое «nil»)? Полностью пустой тип не очень полезен --- хотя C использует пустой тип возвращаемого значения void, чтобы отметить процедуру, которая выполняется только для побочного эффекта, многие другие языки используют для этой цели одноэлементный тип (обычно пустой кортеж).

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

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

Любая цена NULLpointer Используется на C и Java. Это артефакты, присущие реализациям указателей и объектов, и в хорошо продуманном lanugage они не должны допускаться. Во что бы то ни стало дайте своим пользователям путь к продлить существующий тип с нулевым значением, но заставляйте их делать это явно, специально - не заставляйте каждый тип иметь один случайным образом. (В качестве примера явного использования я недавно реализовал тройные деревья поиска Bentley и Sedgewick в Haskell, и мне нужно было расширить тип символа одним дополнительным значением, означающим «не символ». Для этого Haskell предоставляет тип Maybe.)

Наконец, если вы пишете компилятор, это хорошо, чтобы помнить, что самые легкие части языка для компиляции, и те части, которые вызывают наименьшее количество ошибок, являются частями, которые не там :-)

+0

Когда создается массив ссылочного типа, с чем должны сначала заполняться элементы массива? Хотя можно было бы определить язык таким образом, чтобы массив в целом не мог получить доступ до тех пор, пока конструктор не будет запущен для каждого элемента, существует много обстоятельств, когда это действительно не работает очень хорошо; например один имеет массив 'Src' и перестановочное отображение' Permute' и хочет создать новый массив 'Dest', чтобы' Dest [Permute [i]] = src [i] '. Если 'Dest' предварительно заполнен« null », ошибка в' Permute [] 'с меньшей вероятностью останется незамеченной, чем ... – supercat

+0

... если компилятор настаивает на возможности определять значение каждого элемента перед массивом в целом можно получить доступ. Можно было бы правдоподобно утверждать, что затраты на производительность будут перевешиваться преимуществами типа, не имеющего нулевых значений, но имеющего стандартное значение по умолчанию для каждого типа [обратите внимание, что переменная ссылочного типа, которая содержит «null», имеет действительное * значение * даже если эти значения не идентифицируют какой-либо объект], является чрезвычайно ценным в своем собственном праве. – supercat

1

Null - это заполнитель, который означает, что никакая ценность (добавление «правильного типа» для статического типизированного языка) не может быть назначена этой переменной.

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

2

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

Это только одна точка зрения, о которой я не вижу раньше.

3

Null не является проблемой - все, кто лечит и интерпретирует null по-разному, является проблемой.

Мне нравится null. Если бы не было нулевого значения, null был бы заменен другим способом для кода: «У меня нет подсказки, чувак!». (которые некоторые напишут «У меня нет подсказки, человек!», или «У меня нет подсказки, старый боб!» и т. д., и поэтому у нас бы были проблемы с теми же проблемами).

Я обобщаю, знаю.

2

Какую цель дает нуль?

Я считаю, что здесь есть две концепции null.

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

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

У вас есть мысли, особенно за или против null?

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

Нижняя линия, все зависит от целей вашего языка:

  1. целевой аудитории программирования
  2. робастности
  3. производительность
  4. и т.д ...

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

BB

3

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

+0

очень хороший способ выразить тернарную логику - мне это нравится! –

+1

Аргумент против этого, однако, вы возвращаете 3 возможных значения: один для да, один для нет, а другой для не знаю. Но на самом деле, при кодировании с ним, если (a == dontKnow) не имеет значения, если (a == null) сразу после получения значения. За исключением, может быть, другого мыслительного процесса при прямом чтении кода. – Sekhat

1

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

1

Используйте шаблон нулевого объекта!

Если язык ориентирован на объекты, пусть он имеет класс UndefinedValue, из которого существует только один экземпляр singleton. Затем используйте этот экземпляр, где используется null. Это имеет то преимущество, что ваш null будет отвечать на такие сообщения, как #toString и #equals. Вы никогда не столкнетесь с исключением с нулевым указателем, как в Java. (Конечно, для этого требуется, чтобы ваш язык был динамически напечатан).

Смежные вопросы