Последствия не включая NULL на языке?
Я знаю, что NULL не требуется на языке программирования, и я недавно принял решение не включать NULL в свой язык программирования. Инициализация выполняется путем инициализации, поэтому невозможно иметь неинициализированную переменную. Я надеюсь, что это устранит NullPointerException
в пользу более значимых исключений или просто не будет иметь определенных типов ошибок.
Конечно, поскольку язык реализован в C, накрытия будут использоваться NULL.
Мой вопрос заключается в том, что, используя NULL в качестве флага ошибки (это обрабатывается с исключениями) или в качестве конечной точки для структур данных, таких как связанные списки и двоичные деревья (это обрабатывается с дискриминационными объединениями), есть ли какие-либо другие варианты использования для NULL, для которого у меня должно быть решение? Существуют ли какие-либо действительно важные последствия для того, чтобы не иметь NULL, который может вызвать у меня проблемы?
Ответы
Ответ 1
В недавней статье, озаглавленной "Устав" Тони Хоаре под названием Null References: The Billion Dollar Mistake, которая описывает метод, позволяющий присутствие NULL на языке программирования, но также устраняет риск ссылки на такую ссылку NULL. Кажется, это так просто, но это такая мощная идея.
Обновить: здесь ссылка на фактический документ, который я прочитал, в котором говорится о реализации в Eiffel: http://docs.eiffel.com/book/papers/void-safety-how-eiffel-removes-null-pointer-dereferencing
Ответ 2
Заимствование страницы из Haskell Возможно, монада, как вы будете обрабатывать случай возвращаемого значения, которое может или не может существовать? Например, если вы попытались выделить память, но никто не был доступен. Или, может быть, вы создали массив для хранения 50 foos, но ни один из foos еще не был создан - вам нужно каким-то образом проверить эти вещи.
Я думаю, вы можете использовать исключения для охвата всех этих случаев, но означает ли это, что программисту придется обернуть все из них в блок try-catch? В лучшем случае это будет раздражать. Или все должно было бы вернуть свою собственную ценность плюс логическое значение, указывающее, было ли значение действительным, что, безусловно, не лучше.
FWIW, я не знаю ни одной программы, которая не имеет своего рода понятия NULL
- у вас есть NULL
на всех языках C-стиля и Java; Python имеет None
, Scheme, Lisp, Smalltalk, Lua, Ruby all имеют nil
; VB использует Nothing
; и Haskell имеет другой тип Nothing
.
Это не означает, что язык абсолютно должен иметь какой-то нуль, но если все другие большие языки там используют его, наверняка, за ним были некоторые здравые рассуждения.
С другой стороны, если вы делаете только легкий DSL или какой-либо другой не общий язык, вы, вероятно, можете получить без него, если ни один из ваших собственных типов данных не требует этого.
Ответ 3
Тот факт, что сразу приходит в голову, является параметрами pass-by-reference. Я в первую очередь кодер Objective-C, поэтому я привык видеть что-то вроде этого:
NSError *error;
[anObject doSomething:anArgumentObject error:&error];
// Error-handling code follows...
После выполнения этого кода объект error
содержит сведения об обнаруженной ошибке, если таковые имеются. Но скажу, что меня не волнует, происходит ли ошибка:
[anObject doSomething:anArgumentObject error:nil];
Так как я не передаю никакого действительного значения для объекта ошибки, я не получаю никаких результатов назад, и я действительно не беспокоюсь о синтаксическом анализе ошибки (так как вначале мне не важно, если это произойдет).
Вы уже упоминали, что работаете с ошибками по-другому, поэтому этот конкретный пример на самом деле не применяется, но точка стоит: что вы делаете, когда передаете что-то по ссылке? Или ваш язык просто не делает этого?
Ответ 4
Мне кажется полезным использовать метод для возврата NULL - например, для метода поиска, который должен возвращать некоторый объект, он может вернуть найденный объект или NULL, если он не был найден.
Я начинаю изучать Ruby и Ruby имеет очень интересную концепцию NULL, возможно, вы могли бы подумать о внедрении чего-то силимара. В Ruby NULL называется Nil, и это фактический объект, как и любой другой объект. Он реализуется как глобальный объект Singleton. Также в Ruby есть объект False, и оба Nil и False оценивают значение false в булевых выражениях, тогда как все остальные оценивают значение true (даже если, например, значение равно true).
Ответ 5
В моем сознании есть два случая использования, для которых обычно используется NULL:
- Указанная переменная не имеет значения (Nothing)
- Мы не знаем значения рассматриваемой переменной (Неизвестно)
Оба общих события и, честно говоря, использование NULL для обоих может вызвать путаницу.
Стоит отметить, что некоторые языки, которые не поддерживают NULL, не поддерживают ничего из Nothing/Unknown. Например, Haskell поддерживает "Maybe", который может содержать либо значение, либо Nothing. Таким образом, команды могут возвращать (и принимать) тип, который, как они знают, всегда будет иметь значение, или они могут возвращать/принимать "Возможно", чтобы указать, что может не быть значения.
Ответ 6
Я предпочитаю концепцию наличия указателей, не имеющих нулевых значений, по умолчанию, с нулевыми указателями. Вы можете почти сделать это с помощью С++ через ссылки (&), а не указатели, но в некоторых случаях он может быть довольно грубым и раздражительным.
В смысле Java/C язык может работать без нулевого значения, например, Haskell (и большинство других функциональных языков) имеют тип "Maybe", который фактически является конструкцией, которая просто предоставляет концепцию необязательного указателя null.
Ответ 7
Мне непонятно, почему вы хотели бы исключить понятие "null" из языка. Что бы вы сделали, если ваше приложение требует, чтобы вы выполняли инициализацию "лениво" - то есть вы не выполняли операцию до тех пор, пока данные не нужны? Пример:
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), который требует, чтобы они записывали все одинаковые коды проверки ошибок (если (lazyObject.equals(UselessResourceObject)...) или:
-доступайте с некоторым другим значением, которое работает так же, как и null, но имеет другое имя
Для любого сложного/OO-языка вам нужна эта функциональность или что-то в этом роде, насколько я могу судить. Может быть полезно иметь непустой ссылочный тип (например, в сигнатуре метода, так что вам не нужно выполнять нулевую проверку кода метода), но нулевые функции должны быть доступны для случаев, когда вы используйте его.
Ответ 8
Интересная дискуссия здесь происходит.
Если бы я строил язык, я действительно не знаю, есть ли у меня концепция null
. Я думаю, это зависит от того, как я хочу, чтобы язык выглядел. Дело в том, что я написал простой язык шаблонов, основной силой которого являются вложенные токены и легкость создания символического списка значений. Он не имеет понятия null, но тогда он действительно не имеет понятия каких-либо типов, кроме строки.
Для сравнения, langauge, который он встроен, Icon, широко использует null. Вероятно, лучшее, что разработчики языка для Icon сделали с нулевым, делают его синонимом неинициализированной переменной (т.е. Вы не можете отличить переменную, которая не существует, и та, которая в настоящее время имеет значение null). А затем создали два префиксных оператора для проверки значения null и not-null.
В PHP я иногда использую null как "третье" логическое значение. Это хорошо в классах типа "черный ящик" (например, ядро ORM), где состояние может быть True, False или я Do not Know. Null используется для третьего значения.
Конечно, оба этих языка не имеют указателей так же, как и C, поэтому нулевые указатели не существуют.
Ответ 9
Мы постоянно используем нули в нашем приложении для представления "ничего". Например, если вас попросят найти некоторые данные в базе данных с идентификатором, и никакая запись не соответствует этому id: return null. Это очень удобно, потому что мы можем хранить нули в нашем кеше, что означает, что нам не нужно возвращаться в базу данных, если кто-то снова запросит этот идентификатор через несколько секунд.
Кэш сам имеет два разных типа ответов: null, то есть в кэше не было такой записи или объект записи. Объект entry может иметь нулевое значение, которое происходит в случае кэширования нулевого поиска.
Наше приложение написано на Java, но даже с непроверенными исключениями делать это с исключениями было бы невероятно раздражающим.
Ответ 10
Если принять утверждения о том, что у мощных языков должен быть какой-то указатель или ссылочный тип (т.е. что-то, что может содержать ссылку на данные, которые не существуют во время компиляции), а также некоторую форму типа массива (или другие средства имеющий набор слотов для хранения, которые адресуются последовательно с помощью целочисленного индекса), и что слоты последнего должны иметь возможность удерживать первый, и один признает возможность того, что может потребоваться прочитать некоторые интервалы массива указателей/ссылок до разумные значения существуют для всех из них, тогда будут программы, которые с точки зрения компилятора будут считывать слот массива до того, как ему будет написано разумное значение (в общем случае можно выяснить, можно ли прочитать слот массива раньше это будет эквивалентно задаче остановки).
В то время как для языка может потребоваться, чтобы все слоты массива были инициализированы некоторой ненулевой ссылкой, прежде чем кто-либо из них мог быть прочитан, во многих ситуациях нет ничего, что могло бы быть сохранено, что было бы лучше чем null: если делается попытка прочесть еще неписанный слот массива и разыменовать содержащийся в нем элемент (non), который представляет ошибку, и было бы лучше, чтобы системное ловушка находилось в этом состоянии, а не для доступа к произвольным объект, единственная цель которого заключается в том, чтобы предоставить слотам массива некоторую ненулевую вещь, которую они могут ссылаться.