Я не совсем понимаю последовательное избиение нулевых ссылок некоторыми людьми из языков программирования. Что в них плохого? Если я запрашиваю доступ для чтения к файлу, который не существует, тогда я совершенно счастлив получить исключение или нулевую ссылку, и все же исключения считаются хорошими, но нулевые ссылки считаются плохими. В чем причина этого?
programming-languages
exceptions
null
davidk01
источник
источник
Ответы:
Нулевые ссылки больше не «избегают», как исключения, по крайней мере, от тех, кого я когда-либо знал или читал. Я думаю, вы не понимаете общепринятую мудрость.
Что плохо, так это попытка получить доступ к нулевой ссылке (или разыменовать нулевой указатель и т. Д.). Это плохо, потому что это всегда указывает на ошибку; вы никогда бы не сделать что - то подобное на цели, и если вы будете делать это нарочно, то , что еще хуже, потому что это делает его невозможно отличить ожидаемое поведение от багги поведения.
Существуют определенные группы, которые по какой-то причине просто ненавидят концепцию ничтожности, но, как указывает Эд , если у вас ее нет,
null
илиnil
вам просто придется заменить ее чем-то другим, что может привести к чему-то хуже, чем сбой (например, повреждение данных).Фактически, многие структуры охватывают обе концепции; например, в .NET часто встречающийся шаблон - это пара методов, один из которых начинается с префикса
Try
(например,TryGetValue
). В этомTry
случае для ссылки устанавливается значение по умолчанию (обычноnull
), а в другом случае выдается исключение. Нет ничего плохого в любом подходе; оба часто используются в средах, которые их поддерживают.Это действительно все зависит от семантики. Если
null
допустимое возвращаемое значение, как в общем случае поиска в коллекции, вернитеnull
. С другой стороны, если это недопустимое возвращаемое значение - например, при поиске записи с использованием первичного ключа, полученного из вашей собственной базы данных, - возвратnull
будет плохой идеей, поскольку вызывающая сторона не будет ожидать этого и, вероятно, не буду проверять это.На самом деле очень просто выяснить, какую семантику использовать: имеет ли смысл, когда результат функции не определен? Если это так, вы можете вернуть нулевую ссылку. Если нет, бросьте исключение.
источник
null
, так что на самом деле Haskell здесь не имеет никакого значения.null
она так долго терпела, и большинство людей, которые говорят иначе, кажутся учеными с небольшим опытом разработки реальных приложений с такими ограничениями, как неполные требования или возможная согласованность.Большая разница в том, что если вы пропустите код для обработки значений NULL, ваш код, возможно, продолжит аварийно завершаться на более позднем этапе с некоторым несвязанным сообщением об ошибке, где, как и в случае исключений, исключение будет вызвано в начальной точке сбоя (открытие файл для чтения в вашем примере).
источник
Потому что нулевые значения не являются необходимой частью языка программирования и являются постоянным источником ошибок. Как вы говорите, открытие файла может привести к сбою, который может быть возвращен либо как нулевое возвращаемое значение, либо через исключение. Если нулевые значения не были разрешены, то существует непротиворечивый, единственный способ сообщить об ошибке.
Кроме того, это не самая распространенная проблема с нулями. Большинство людей не забывают проверять наличие нуля после вызова функции, которая может ее вернуть. Проблема возникает гораздо чаще в вашем собственном проекте, позволяя переменным быть нулевыми в различные моменты выполнения вашей программы. Вы можете создать свой код так, чтобы нулевые значения никогда не допускались, но если бы нулевые значения не были разрешены на уровне языка, ничего из этого не потребовалось бы.
Однако на практике вам все равно потребуется какой-то способ указать, инициализирована ли переменная или нет. Тогда у вас будет ошибка, в которой ваша программа не аварийно завершится, а вместо этого продолжит работу, используя какое-то недопустимое значение по умолчанию. Я, честно говоря, не знаю, что лучше. За свои деньги я люблю рано и часто падать.
источник
null
возвращаемое значение: запрошенная вами информация не существует. Там нет разницы. В любом случае, вызывающий объект должен проверить возвращаемое значение, если ему действительно нужно использовать эту информацию для какой-то конкретной цели. Будь то проверкаnull
, нулевой объект или монада, практически не имеет значения.Тони Хоар, который создал идею нулевой ссылки, называет ее ошибкой в миллион долларов .
Проблема не в нулевых ссылках как таковых, а в отсутствии надлежащей проверки типов в большинстве (в противном случае) безопасных для типов языков.
Это отсутствие поддержки со стороны языка означает, что ошибки "нулевые ошибки" могут скрываться в программе в течение длительного времени, прежде чем их обнаружат. Такова природа ошибок, конечно, но теперь известно, что «нулевых ошибок» можно избежать.
Эта проблема особенно проявляется в C или C ++ (например) из-за «жесткой» ошибки, которую она вызывает (немедленное аварийное завершение программы без элегантного восстановления).
На других языках всегда возникает вопрос, как с ними справиться.
В Java или C # вы получите исключение, если попытаетесь вызвать метод по нулевой ссылке, и это может быть нормально. И поэтому большинство программистов на Java или C # привыкли к этому и не понимают, почему кто-то хотел бы поступить иначе (и смеяться над C ++).
В Haskell вы должны явно предоставить действие для нулевого случая, и поэтому программисты на Haskell злорадствуют своим коллегам, потому что они поняли это правильно (правильно?).
Это, действительно, старые дебаты о коде ошибки / исключении, но на этот раз со значением Sentinel вместо кода ошибки.
Как всегда, то, что наиболее уместно, зависит от ситуации и семантики, которую вы ищете.
источник
null
на самом деле это зло, потому что оно подрывает систему типов . (Конечно, у альтернативы есть недостаток в ее многословности, по крайней мере, в некоторых языках.)Вы не можете прикрепить понятное человеку сообщение об ошибке к нулевому указателю.
(Однако вы можете оставить сообщение об ошибке в файле журнала.)
В некоторых языках / средах , которые позволяют арифметику указателей, если один из указателей аргумента равно нулю , и это допускается в расчет, то результат был бы недействительным , не нулевой указатель. (*) Больше силы для вас.
(*) Это часто случается в программировании COM , где, если вы попытаетесь вызвать метод интерфейса, но указатель интерфейса будет нулевым, это приведет к вызову неверного адреса, который почти, но не совсем, совершенно не похож на ноль.
источник
Возврат NULL (или числового нуля, или логического false) для сигнализации об ошибке неверен как технически, так и концептуально.
Технически, вы обременяете программиста проверкой возвращаемого значения сразу же , в точном месте, где оно возвращается. Если вы открываете двадцать файлов подряд и сигнализация об ошибках выполняется путем возврата значения NULL, то код потребления должен проверять каждый файл, прочитанный по отдельности, и исключать любые циклы и подобные конструкции. Это идеальный рецепт для загроможденного кода. Однако, если вы решите сообщить об ошибке, выдав исключение, потребительский код может решить обработать исключение немедленно или позволить ему всплыть на столько уровней, сколько необходимо, даже при вызовах функций. Это делает код намного чище.
Концептуально, если вы открываете файл и что-то идет не так, то возвращать значение (даже NULL) будет неправильно. Вам не нужно ничего возвращать, потому что ваша операция не закончилась. Возвращение NULL является концептуальным эквивалентом «Я успешно прочитал файл, и вот что он содержит - ничего». Если это то, что вы хотите выразить (то есть, если NULL имеет смысл как фактический результат для рассматриваемой операции), то непременно верните NULL, но если вы хотите сообщить об ошибке, используйте исключения.
Исторически, об ошибках сообщалось таким образом, потому что языки программирования, такие как C, не имеют встроенной в язык обработки исключений, и рекомендуемый способ (с использованием длинных переходов) является немного сложным и немного нелогичным.
Существует также сторона обслуживания проблемы: за исключением, вы должны написать дополнительный код для обработки ошибки; если вы этого не сделаете, программа рано и сильно потерпит неудачу (что хорошо). Если вы возвращаете NULL, чтобы сигнализировать об ошибках, поведение программы по умолчанию - игнорировать ошибку и просто продолжать, пока она не приведет к другим проблемам в будущем - поврежденным данным, segfaults, NullReferenceExceptions, в зависимости от языка. Чтобы сообщить об ошибке рано и громко, вам нужно написать дополнительный код и угадать, что: это та часть, которая не учитывается, когда вы находитесь в сжатые сроки.
источник
Как уже указывалось, многие языки не преобразуют разыменование нулевого указателя в перехватываемое исключение. Делать это - относительно современный трюк. Когда проблема с нулевым указателем была впервые обнаружена, исключения еще даже не были изобретены.
Если вы допустите нулевые указатели в качестве допустимого случая, это особый случай. Вам нужна специальная логика обработки, часто в разных местах. Это дополнительная сложность.
Связано ли это с потенциально нулевыми указателями или нет, если вы не используете выбросы исключений для обработки исключительных случаев, вы должны обработать эти исключительные случаи другим способом. Как правило, каждый вызов функции должен иметь проверки для этих исключительных случаев, либо для предотвращения неправильного вызова вызова функции, либо для обнаружения случая сбоя при выходе из функции. Это дополнительная сложность, которую можно избежать, используя исключения.
Большая сложность обычно означает больше ошибок.
Альтернативы использованию нулевых указателей в структурах данных (например, для отметки начала / конца связанного списка) включают использование элементов дозорного. Они могут дать ту же функциональность с гораздо меньшей сложностью. Однако могут быть и другие способы управления сложностью. Один из способов заключается в том, чтобы обернуть потенциально нулевой указатель в классе интеллектуальных указателей так, чтобы проверки на нуль были необходимы только в одном месте.
Что делать с нулевым указателем, когда он обнаружен? Если вы не можете встроить обработку исключительного случая, вы всегда можете вызвать исключение и эффективно делегировать эту обработку специального случая вызывающей стороне. И это именно то, что некоторые языки делают по умолчанию, когда вы разыменовываете нулевой указатель.
источник
Специфично для C ++, но там нулевые ссылки избегаются, потому что нулевая семантика в C ++ связана с типами указателей. Вполне разумно, чтобы функция открытия файла не работала и возвращала нулевой указатель; на самом деле
fopen()
функция делает именно это.источник
Это зависит от языка.
Например, Objective-C позволяет вам отправлять сообщение нулевому (nil) объекту без проблем. Вызов nil также возвращает nil и считается особенностью языка.
Мне лично это нравится, поскольку вы можете положиться на это поведение и избегать всех этих замысловатых вложенных
if(obj == null)
конструкций.Например:
Можно сократить до:
Короче говоря, это делает ваш код более читабельным.
источник
Я не буду кричать, возвращаете ли вы нулевое значение или выбрасываете исключение, если вы его документируете.
источник
GetAddressMaybe
илиGetSpouseNameOrNull
.Нулевая ссылка обычно возникает из-за того, что что-то в логике программы было пропущено, т.е. вы попали в строку кода, не пройдя необходимую настройку для этого блока кода.
С другой стороны, если вы генерируете исключение для чего-то, это означает, что вы узнали, что при нормальной работе программы может возникнуть определенная ситуация, и она обрабатывается.
источник
Пустые ссылки часто очень полезны: например, элемент в связанном списке может иметь преемника или не иметь преемника. Использование слова
null
«нет преемника» совершенно естественно. Или, у человека может быть супруг или нет - использование словаnull
«человек не имеет супруга» является совершенно естественным, гораздо более естественным, чем наличие некоторого «не имеет супруга» - особая ценность, на которуюPerson.Spouse
может ссылаться член.Но: многие значения не являются обязательными. В типичной ООП-программе я бы сказал, что более половины ссылок не может быть
null
после инициализации, иначе программа потерпит неудачу. В противном случае код должен быть пронизанif (x != null)
проверками. Так почему каждая ссылка должна быть обнуляемой по умолчанию? На самом деле все должно быть наоборот: переменные по умолчанию должны быть не обнуляемыми, и вы должны явно сказать «о, и это значениеnull
тоже может быть ».источник
Ваш вопрос сформулирован до смешного. Вы имеете в виду исключение нулевой ссылки (которое на самом деле вызвано попыткой дессылка нулевая)? Явная причина не желать такого типа исключений состоит в том, что он не дает никакой информации о том, что пошло не так, или даже когда - значение могло быть установлено равным нулю в любой точке программы. Вы пишете «Если я запрашиваю доступ для чтения к файлу, который не существует, я совершенно счастлив получить исключение или нулевую ссылку» - но вы не должны быть совершенно счастливы получить что-то, что не указывает на причину , Нигде в строке «попытка разыменования null» не упоминается о чтении или несуществующих файлах. Возможно, вы имеете в виду, что вы были бы совершенно счастливы получить нулевое значение в качестве возвращаемого значения от вызова чтения - это совсем другой вопрос, но он все еще не дает вам никакой информации о том, почему чтение не удалось; Это'
источник