Последствия не включения NULL в язык? - PullRequest
13 голосов
/ 18 сентября 2009

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

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

Мой вопрос, кроме использования NULL в качестве флага ошибки (это обрабатывается с исключениями) или в качестве конечной точки для структур данных, таких как связанные списки и двоичные деревья (это обрабатывается с помощью различимых объединений), есть ли другие варианты использования для NULL, для которого у меня должно быть решение? Есть ли действительно важные последствия отсутствия NULL, которые могут вызвать у меня проблемы?

Ответы [ 10 ]

8 голосов
/ 18 сентября 2009

Есть недавняя статья, на которую ссылается Тони Хоар на LtU под названием Null References: The Billion Dollar Error Error , в которой описывается метод, позволяющий присутствовать NULL в языке программирования, но также исключает риск ссылки на такую ​​пустую ссылку. Кажется, все так просто, но это такая мощная идея.

Обновление : вот ссылка на реальную статью, которую я прочитал, в которой рассказывается о реализации в Eiffel: http://docs.eiffel.com/book/papers/void-safety-how-eiffel-removes-null-pointer-dereferencing

3 голосов
/ 18 сентября 2009

Заимствование страницы из Монада Возможно Хаскелла , как вы будете обрабатывать возвращаемое значение, которое может существовать или не существовать? Например, если вы пытались выделить память, но ни одна не была доступна. Или, возможно, вы создали массив для хранения 50 foos, но ни один из foos еще не был создан - вам нужен какой-то способ, чтобы иметь возможность проверять подобные вещи.

Полагаю, вы можете использовать исключения, чтобы охватить все эти случаи, но означает ли это, что программисту придется обернуть все из них в блок try-catch? Это было бы в лучшем случае раздражающим. Или все должно было бы возвращать свое собственное значение плюс логическое значение, указывающее, было ли значение допустимым, что, безусловно, не лучше.

FWIW, я не знаю ни одной программы, у которой нет некоторого вида понятия NULL - у вас есть null во всех языках стиля C и Java ; Python имеет None, Scheme, Lisp, Smalltalk, Lua, Ruby - все имеют nil; VB использует Nothing; и у Haskell есть другой вид nothing.

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

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

1 голос
/ 18 сентября 2009

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

Я начинаю изучать Ruby, и у Ruby есть очень интересная концепция для NULL, возможно, вы могли бы подумать о реализации чего-то silimar. В Ruby NULL называется Nil, и это реальный объект, как и любой другой объект. Оказывается, он реализован как глобальный объект Singleton. Также в Ruby есть объект False, и Nil и False оцениваются как false в логических выражениях, тогда как все остальное оценивается как true (даже 0, например, оценивается как true).

1 голос
/ 18 сентября 2009

То, что сразу приходит на ум, это параметры передачи по ссылке. Я в первую очередь программист Objective-C, поэтому я привык видеть такие вещи:

NSError *error;
[anObject doSomething:anArgumentObject error:&error];
// Error-handling code follows...

После выполнения этого кода объект error содержит сведения об обнаруженной ошибке, если таковая имеется. Но скажите, что мне все равно, если произойдет ошибка:

[anObject doSomething:anArgumentObject error:nil];

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

Вы уже упоминали, что обрабатываете ошибки другим способом, так что этот конкретный пример на самом деле не применим, но главное: что вы делаете, когда передаете что-то по ссылке? Или ваш язык просто так не делает?

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

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

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

0 голосов
/ 02 ноября 2009

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

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

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

0 голосов
/ 18 сентября 2009

Интересная дискуссия происходит здесь.

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

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

В PHP я иногда использую null в качестве «третьего» логического значения. Это хорошо в классах типа «черный ящик» (например, ядро ​​ORM), где состояние может быть True, False или I Not Know. Нуль используется для третьего значения.

Конечно, оба эти языка не имеют указателей так же, как C, поэтому нулевые указатели не существуют.

0 голосов
/ 18 сентября 2009

Мне не понятно, почему вы хотите исключить из языка понятие «ноль». Что бы вы сделали, если ваше приложение требует, чтобы вы выполняли некоторую инициализацию «лениво», то есть вы не выполняете операцию до тех пор, пока не потребуются данные? Пример:

public class ImLazy {
 public ImLazy() {
  //I can't initialize resources in my constructor, because I'm lazy.
  //Maybe I don't have a network connection available yet, or maybe I'm
  //just not motivated enough.
 }

 private ResourceObject lazyObject;
 public ResourceObject getLazyObject() { //initialize then return
  if (lazyObject == null) {
   lazyObject = new DatabaseNetworkResourceThatTakesForeverToLoad();
  }
 }

 public ResourceObject isObjectLoaded() { //just return the object
  return (lazyObject != null);
 }
}

В таком случае, как мы можем вернуть значение для getObject ()? Мы могли бы придумать одну из двух вещей:

- требуется, чтобы пользователь инициализировал LazyObject в объявлении. Затем пользователь должен будет заполнить некоторый фиктивный объект (UselessResourceObject), который требует от него написать все тот же код проверки ошибок (if (lazyObject.equals (UselessResourceObject) ...) или:

- получить другое значение, которое работает так же, как null, но имеет другое имя

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

0 голосов
/ 18 сентября 2009

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

Язык может обойтись без нуля в смысле Java / C, например, Haskell (и большинство других функциональных языков) имеют тип «Maybe», который фактически является конструкцией, которая просто предоставляет концепцию необязательного нулевого указателя. *

0 голосов
/ 18 сентября 2009

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

  • Рассматриваемая переменная не имеет значения (Nothing)
  • Мы не знаем значение рассматриваемой переменной (Неизвестно)

Обе распространенные ситуации и, честно говоря, использование NULL для обоих могут вызвать путаницу.

Стоит отметить, что некоторые языки, которые не поддерживают NULL, поддерживают ничего из Nothing / Unknown. Haskell, например, поддерживает «Maybe», которое может содержать либо значение, либо Nothing. Таким образом, команды могут возвращать (и принимать) тип, который, как они знают, всегда будет иметь значение, или они могут возвращать / принимать «Возможно», чтобы указать, что значение может отсутствовать.

...