Я думаю, что краткое изложение того, почему null является нежелательным, заключается в том, что бессмысленные состояния не должны быть представлены.
Предположим, что я моделирую дверь. Он может находиться в одном из трех состояний: открыт, закрыт, но разблокирован, закрыт и заблокирован. Теперь я мог моделировать его вдоль линий
class Door
private bool isShut
private bool isLocked
и ясно, как отобразить мои три состояния в этих двух логических переменных. Но это оставляет четвертое, нежелательное состояние: isShut==false && isLocked==true
. Поскольку типы, которые я выбрал, так как мое представление допускает это состояние, я должен приложить умственные усилия, чтобы гарантировать, что класс никогда не попадает в это состояние (возможно, явно кодируя инвариант). В отличие от этого, если бы я использовал язык с алгебраическими типами данных или проверяемых перечислений, что позволяет мне определить
type DoorState =
| Open | ShutAndUnlocked | ShutAndLocked
тогда я мог бы определить
class Door
private DoorState state
и нет больше забот. Система типов гарантирует, что существует только три возможных состояния для экземпляра class Door
. Это то, к чему подходят системы типов - явно исключая целый класс ошибок во время компиляции.
Проблема с null
заключается в том, что каждый ссылочный тип получает это дополнительное состояние в своем пространстве, которое обычно нежелательно. А переменной string
может быть любая последовательность символов, или это может быть это сумасшедшее дополнительное значение null
, которое не отображается в моей проблемной области. Triangle
объект имеет три Point
с, которые сами по себе имеют X
и Y
значения, но, к сожалению, Point
s или сам Triangle
может быть это сумасшедшее нулевое значение, что не имеет смысла в области построения графиков я работаю в п.
Когда вы намереваетесь моделировать возможное несуществующее значение, вы должны выбрать его явно. Если так, как я намерен моделировать людей в том, что каждый Person
имеет FirstName
и LastName
, но только у некоторых людей есть MiddleName
с, то я хотел бы сказать что-то вроде
class Person
private string FirstName
private Option<string> MiddleName
private string LastName
где string
здесь предполагается быть непустой тип. Тогда нет никаких сложных инвариантов для установления и отсутствия неожиданных NullReferenceException
s при попытке вычислить длину чьего-либо имени. Система типов гарантирует, что любой код, относящийся к MiddleName
, учитывает возможность его None
, тогда как любой код, относящийся к FirstName
, может с уверенностью предположить, что там есть значение.
Так, например, с использованием типа выше, мы могли бы автору эту глупую функцию:
let TotalNumCharsInPersonsName(p:Person) =
let middleLen = match p.MiddleName with
| None -> 0
| Some(s) -> s.Length
p.FirstName.Length + middleLen + p.LastName.Length
без забот.В отличие от этого, в языке с обнуляемого ссылки на типы, такие как строки, то при условии,
class Person
private string FirstName
private string MiddleName
private string LastName
вы в конечном итоге авторинга такие вещи, как
let TotalNumCharsInPersonsName(p:Person) =
p.FirstName.Length + p.MiddleName.Length + p.LastName.Length
, который взрывается, если входящий объект Person не имеет инвариант все время ненулевым, или
let TotalNumCharsInPersonsName(p:Person) =
(if p.FirstName=null then 0 else p.FirstName.Length)
+ (if p.MiddleName=null then 0 else p.MiddleName.Length)
+ (if p.LastName=null then 0 else p.LastName.Length)
или, может быть
let TotalNumCharsInPersonsName(p:Person) =
p.FirstName.Length
+ (if p.MiddleName=null then 0 else p.MiddleName.Length)
+ p.LastName.Length
Предполагая, что p
обеспечивает первое/последнее, но среднее может быть нулевым, или, может быть, вы делаете проверки, которые генерируют разные типы исключений или кто знает что. Все эти сумасшедшие варианты реализации и вещи, о которых нужно подумать, возникают из-за того, что есть эта глупая представляемая ценность, которую вы не хотите или не хотите.
Null обычно добавляет ненужную сложность. Сложность является врагом всего программного обеспечения, и вы должны стремиться к уменьшению сложности всякий раз, когда это разумно.
(Обратите внимание также, что есть более сложность для даже этих простых примеров. Даже если FirstName
не может быть null
, string
может представлять ""
(пустая строка), который, вероятно, также не имя человек, который мы намерены смоделировать . Таким образом, даже с не-нулевыми строками, все же может быть, что мы «представляем бессмысленные значения». Опять же, вы можете выбрать сражение с этим либо с помощью инвариантов и условного кода во время выполнения, либо с помощью системы типов (например, иметь тип NonEmptyString
). Последнее, возможно, не рекомендуется («хорошие» типы часто «закрыты» по совокупности общих операций, и, например, NonEmptyString
не закрыт над .SubString(0,0)
), но он демонстрирует больше точек в дизайне В конце дня, в любая система данного типа, есть некоторая сложность, от которой будет очень хорошо избавиться, и другую сложность, из-за которой сложнее всего избавиться. Ключом к этой теме является то, что в почти каждой системе изменение от «нулевых ссылок по умолчанию» к «непустым ссылкам по умолчанию» почти всегда является простым изменением, что делает систему типов намного лучше при сражении сложность и исключение определенных типов ошибок и бессмысленных состояний. Так что это довольно сумасшествие, так что многие языки повторяют эту ошибку снова и снова.)
Если добавить теги к этому вопросу для функционально-программирования или F # вы обязаны получить некоторые фантастические ответы. –
Я добавил функциональный тег программирования, так как тип опции действительно поступал из мира ml. Я бы предпочел не отмечать его F # (слишком специфичным). Кстати, кому-то с таксономическими полномочиями необходимо добавить теги типа «тип-тип» или «тип-тип». –
, я подозреваю, что таких особых тегов мало. Теги, в основном, позволяют людям находить соответствующие вопросы (например, «вопросы, которые я знаю много, и я смогу ответить», и «функциональное программирование» здесь очень полезно. Но что-то вроде «null» или «null», option-type "гораздо менее полезны. Немногие люди, вероятно, будут отслеживать тег типа« option-type », который ищет ответы на вопросы, которые они могут ответить.;) – jalf