В 1972 году три популярных компьютерных ученных написали книгу Структурное Программирование, где они упомянули частные неструктурированные типы:
Все структурированные данные в последнем исследовании должны быть построены из неструктурированных компонентов, принадлежащих к примитивам или неструктурированным типам. Некоторые из этих неструктурированных типов (например, вещественные числа и целые числа) могут быть взяты как данное в языке программирования или железной части (прим. hardware) компьютера. Хотя эти примитивные типы теоретически подходят для всех случаев, здесь есть сильные практичные причины для содействия программисту обозначить его собственные неструктурированные типы для того, чтобы сделать ясными его намерения об потенциальных границах значений переменной и интерпретации каждого такого значения; и чтобы допустить последующий дизайн эффективного представления.
(...) Такой тип называют перечислением (прим. enumeration), и мы советуем стандартную нотацию для имени типа и ассоциации имени типа с каждым из его альтернативных значений.
`
type suit = (club, diamond, heart, spade);
(...)
type year = 1900… 1960;
type coordinate = 0… 1023;
`
(...) Мы, следовательно, вводим правило где a… b обозначает диапазон значений между a и b включительно. Это известно как поддиапазон/подгруппы (прим. subrange) типа, к которому принадлежат a и b, (...)(на английском)
Ole-Johan Dahl, Edsger W. Dijkstra, C.A.R. Hoare, Structured Programming, A.P.I.C. Studies in Data Processing, No. 8, 1972, p.97
Некоторые языки в самом деле поддерживают подгрупповые типы, например Ada и Delphi. Тем не менее, современные популярные языки, такие как Java и C# прямо не поддерживают неструктурированные частные подгрупповые типы.
В дополнение к этому существует огромное недопонимание между декларацией типа и его реальным значением. Например, в .NET Array принимает Integer как индекс в диапазоне [-2^31, 2^31], поэтому мы декларируем поддержку для чисел -1,-2,… как значений индекса. В это же время допустимы только неотрицательные числа, т.е. [0, 2^31]. Для честного и ясного кода должно быть обозначение Array[NonnegativeInteger].
Более того, часто используемые структурированные и неструктурированные типы не ограничиваются числами. Сегодня email часто представляют в виде типа String:
function void SendEmail(String email, String emailBody){ ... }
хотя на самом деле мы имеем ввиду
function void SendEmail(EmailAddress email, String emailBody){ ... }
Делая допущение, что каждый объект класса/структуры EmailAddress является всегда верным, мы более не должны проверять строку каждый раз с помощником IsEmail() или атрибутом DataAnnotations (в .NET). Он может иметь функцию function EmailAddress TryConvert(String email) для удобного конвертирования из строки.
Другие типичные места для очевидных улучшений:
- Имена
Проверка имени типа String для имени и фамилии среди всей программы с теми же ограничениями, возможно с не более чем 256 специальными символами и не менее одного символа, может быть заменено на то, что в действительность имеет ввиду программист: class/structure Name. - class Description с общими правилами для контактных сообщений, комментариев к заказу, сообщений с отзывами, и т. д.
- Меры: градусы, координаты, вес, и т. д.
- Дата и время
Числа вплоть до 2147483648 (2^31) для года, месяца, дня, часа и минуты кажутся не удобными в реальном использовании и многие системы в конце концов выкинут ошибку, используя большие числа для этих типов. - Деньги
Не существует банкноты в минус $100, но может существовать понятие долга в $100.
С помощью Контрактного Дизайна (Design by Contracts) большинство проверок могут быть сделаны во время компиляции. Для совместимости с другими системами частные типы должны быть построены из примитивных и простых типов, как Integer и String, а также быть конвертируемыми из этих типов.
Автор: a-artur