Лекция 5 (1160838)
Текст из файла
14
Лекция 5.
Пункт 2.4 Ограниченный тип данных.
2.4.1 Перечислимый Тип Данных.
Из широко известных ЯП перчислимый тип данных впервые появился в 1969 году в ЯП Pascal1. (Курс Никлауса Вирта для студентов). После этого перечислимый тип данных триумфально прошел по всем известных ЯП.
Синтаксис довольно общий:
Type EnumType=(val1, …, valN);
Перечислимый тип данных отлично подходит под концепцию «множества значений». Фактически это разновиднось численных констант. К ним применимы операции =, <>, <, >, <=, >= (они упорядочены) .
succ(x) – дает следующий элемент перечислимого типа(неопределен для последнего по номеру элемента)
pred(x) – дает предыдущий элемент перечислимого типа(неопределен для первого по номеру элемента)
Если есть функция ord(x)- 0..N-1 – возвращает колчиство констант перед данным элементом х. Важны именно:
-
Упорядоченность
-
То, что каждый элемент имеет название
В памяти компьютера названия хранятся как целые числа.
Замечание. На практике иногда возникают так называемые magic number
54
FFFE – Unicode-овская константа, показывающая, каков порядок байтов(в двухбайтовом хранении) – бывает тупоконечный и остроконечный порядок(в зависимости от того, где хранятся младшие и старшие байты)
В любом случае появление такого рода констант в коде i!=54 – неряшливость программиста(У хорошего программиста в коде могуут быть только 3 неименованные константы: 0, 1 и -1, а остальные должны быть именованы). В случае, если значение константы неинтересно, а интересен порядок, следует вспомнить о UnicodeMark.
Наличие особого перечислимого типа данных, не смешивающегося целочисленным, увеличивает
-
Надежность программы
-
Ее читабельность
-
Самодокументацию(чтобы никуда не лезть - ведь главный минус документации в том, что она редко когда соответствует программному тексту, точно так же как help далеко не всегда соответствует системному развитию и не всегда адекватен содержанию.)
Интересно, что даже в таком ЯП, как Си(стандарт 89 – ANSII C) –перечислимый тип данных появился, хотя его понятие противоречило ЯП Си. Ведь Си – это ассемблер, где никакого аналога перечислимого типа нет.
Пример.
Рассмотрим различные преобразования.
X:EnumType; C:integer;//safe
X:EnumType; C:integer;//unsafe
Преобразование из перечислимого типа в целый – безопасное, а преобразование из целого типа в перечислимый - опасное
Подход таков: присваивание произвольного целого типа в ограниченный диапазон(а перечисление – это ограниченный диапазон) – опасное преобразование.А при произвольном присваивании должна производиться проверка. Такая проверка называется квазистатитеской( выполняется во время выполнения программы).
Пример:
Х: 0..N-1
X:= expr;// (*)
Если компилятор допускает (*) - приваивание, то в этом месте компилятор вставляет проверку:
if((expr>=N) or (expr<0))
then error();//образно говоря
Если expr можно знать до выполнения, они выполняются и проверяются до выполнения. Если невозможно узнать значение выражение до выполнения программы, то компилятор генерирует соответствующий код.
Замечание. Квазистатического контроля, кстати, нет ни в одном машинном ЯП
(а деление на 0? Квазистатическая проверка – это extra-случай)
Любая команда в машинном ЯП просто транслируется. Именно поэтому в ЯП Си нет квазистатической проверки.
a[-1] – удовлетворяет синтаксису. Семантика не определена, но компилятор не имеет право даже ругаться, ибо вставка квазистатического кода противоречит сути ассемблера.
Впрочем, квазистатические проверки в Си уровня после 90-х годов появились.(именно поэтому концепция массивов оказалась очень ненадежной).
Не случайно RTTI в С++ появились только в 90-х годы, т. к.
-
Программисты активно использовали идентификацию типа данных
-
Программисты все равно вставляли в компиляторы данные проверки
-
Библиотеки сильно расползались.
Замечание.
Любая квазистатическая проверка осуществляется во время выполнения.
Не случайно во всех ЯП перечислимый тип данных – упорядоченный.
Как же они влезли в ЯП Си?
enum T1(v0, …, vN)
-это лишь короткий способ задания целочисленной константы, авносильной
#define v0 0
……..
#define vN N-1
Да, вы скажете, что у нас появилось имя нового типа, но компиятор-тон а себя никаких обязательств не взял. В результате ценность перечислимых типов теряется.
Вывод:
В Си 89 – компактный способ задания констант от 0 до N.
Начиная с Pascal, почти в каждый ЯП включался перечисимый тип данных, и ничем кроме плюсов, он, казалось бы, не обладал.
И вдруг в 198 году Никлаус Вирт публикует описание ЯП Оберон(а в 1993 – Оберон-2). Перечислимых типов данныых там не было и в помине. Это было довольно странно, до этого перечислимые типы появлялись даже там, где ои вовсе были не нужны.
Никлаус Вирт первым ввел перечислимый тип и первым же отказался от него.
Главное проектное решение ЯП Оберон:
В Яп должны присутствовать лишь те конструкции, без которых его функционирование в конкретной программной нише невозможно.
Что же не понравилось Никлаусу Вирту в перечислимом типе? Ведь он обеспечивает надежность и читабельность. Исходя из принципа минимальности: с точки зрения технологичности в ЯП Оберон главное: расширение типов- наследование. Заметим, что динамического полиморфизма в первой версии ЯП Оберон не было.
Противоречат ли концепции перечислимого типа данных концепции перечисимого типа?
При переопределении типов(методов) в исходных классах может увеличиться и набор значений, и набор параметров.
ET! Метод
-
С точки зрения Вирта, перечислимый тип данных противоречит концепции расширения типа данных
-
Понятие импорта(аналогично понятию uses в Turbo Pascal) – с точки зрения импорта, что происходитпри импортировнии enumtype?
Одновременно с этим задается(передается, импортируется) и все значения константы.
Значения констант могут пересекаться – неявный импорт всех прочих значений.
Тенденция 90-х гг
Дизайн Яп меняется.
1995 год – появление Java. Перечислимого типа данных еще не было. Им приходит конец.
Замечание.
Правда, в 1999 году появляется С#, и там перечислимые типы данных были. Создатели, однако же, должны были оправдаться, почему они включили перечислимый тип данных в свой ЯП. Дело в том, что в польу перечислимых типов появился еще 1 аспект: визуальность проектирования в виртуальных средах. При рисовании форм и набрасывании на них элементов управления, таймеров, архиваторов, в любой визуальной среде проектирования мы можем редактировать свойства компоненты*частота срабатывания, вкл/выкл и т. д.
Пример: у свойства выранивания текста может, к примеру, быть 3 значения: по левому краю, по правому краю, по центру. Естественным образом соответствующее свойство должно принадлежать некоторому перечислимому типу данных.(А если int, то мы должны помнить, что, к примеру, означает 1, что 2, а что – 3.)И это свойство, более того, является самоаргументированным.Таким образом,
-
Сразу видно, ккие есть альтернативы(понятность)
-
Неверную альтернативу мы просто не можем внести
довольно сильные аргументы в пользу перечислимого типа данных в этой области.
Выполняется и свойство «закрытости» типа данных.
Что интересно, в дальнейшем тенденция по далению перечислимых типов данных сошла на нет.
2006 год - новая редакция языка Java.(существенно не менявшая свои основные концепции в течение 10 лет). Период стабильности Java кончился. Многое было добавлено в язык, в том числе и перечислимые типы данных. И это происходит не только из-за развития средств визуального проектирования: постепенно меняется парадигма программирования
.
1972 год – SmallTalk
1979, 1983 год – C++
1988 год – Turbo Pascal 5.5
До этого:
80-е гг – Object Pascal
Objective Cи и т д.
Конец 80-х - начало 90-х гг – появление ОО ЯП(главная мода).
В течение 20-ти с лишним лет развитие ЯП шло в рамках с ОО ЯП. Что происходит в последние десятилетия? Стало ясно, что никакая парадигма программирования не решит всех проблем. В данном сллучае нужна уже не иерархия классов, нужен «черный ящик» с лампочками и учками – и это называется компонентой.
Первая компонента появилась в Visual Basic(отнюдь не обьектно-ориентированная!):
Visual Basic Extension (VBX)
Использовать компоненты намного проще. Лампочки – это properties, а ручки – methods.
(«Дайте мне компоненту, и я буду ей управлять. Остальное – неважно, и как она устроена – совершенно неважно.»)
Если мы хотим разработать иерархию классов, разрабатывать, очевидно, надо хорошо. Плохо – не надо(пользоваться никто не будет.)
Вывод: проектировать иерархию, чтобы от нее потом можно бло виртуальным образом наследоваться – сложно. 20 лет развития ОО ЯП привели к тому, что по умолчанию в языке C# перед классом стоит слово sealed(запрет наследования):
sealed public X{……}
От класса Х уже ничего нельзя наследовать.
Главный вывод: компонентное программирование не менее важно, чем обьектно-ориентированное, поэтому не следует полностью отказываться от перечислимого типа данных.
1)Представления(значение), эффективность.
В некоторых случаях важно значение обьектов перечислимого типа, а в некоторых – упорядочивание. Какие тут есть проблемы?
1. управления представлением перечислимого типа
2. преобразования(в int и обратно)
3. появление импортированых имен(при импортировании имен мы импортируем еще и константы возможен конфликт имен)
4. проблема удобства использования(ввод/вывод и т. п.): всякий, кто пытался на Pascal ввести или вывести значения перечислимого типа, сталкивался с трудностями. Имена-то у нас есть, но информация о них теряется.
Пример
Мodula-2: TYPE ET=(V1, …, VN)
Появляются 2 функции:
ord(X): ETINTEGER
Никакого управления представлением в ЯП Modula-2 нет.
Явная функция: ord.
Псевдо-функция: val(T, i)
Первый аргумент T- обьект перечислимого типа
Второй аргумент I – номер.
Если i>=N и i<1, то данная функция выдает ошибку.
Перечислимый тип в С++
Без перечислимого типа данных в С++ никак нельзя. В С++ концепция перечислимого типа данных была расширена:
1 – они стали полноценными типами данных
enum ET{…};
Могли, к примеру, бть типом формальных и фактических параметров функции:
void f(ET x);
void f(int x);
С точки зрения языка Си это псевдо-вопрос. Это ничего не меняет и ничего не дает.
typedef int c;
С точки зрения С++ это намного важнее: возникает вопрос, как быть с перегрузкой. Как только появляется понятие перегрузки(важно для удобства – ведь новые типы данных должны быть эквивалентны по удобству встроенным я ЯП типам данных)
Из соображений совместимости любой перечислимый тип занимает рахмер intа.
Замечание. Еще в С++ появилось такое замечательное новшество:
Enum FileAccept
{
FileRead=1;
FileWrite=2;
FileReadWrite= FileRead|FileWrite;
}.
-к данным перечислимого типа тепер можно применять побитовые и иные арифметические операции.
Ввод-вывод из соображений совместимости для перечислимого типа сделали такой же, как и у inta. Однако первые три проблемы остались
Перечислимый тип в Ada
Перечислимый тип в Ада занимает особое место. Печречислимые типы данных не встроены в ЯП, это есть типы библиотеки. Любая программа на языке Ада – часть пакета STANDART и ей доступны все имена из данного пакета.
Рассмотрим пару типов данных из языка Ада.
BOOLEAN - является перечислмым типом данных.
CHARACTER – тоже перечислимый тип данных.
Тут же возникает проблема конфликта имен, возникающего при неявном импорте.
Создатели Ады решили, что конфиликт имен может быть всегда. То возможна и такая ситуация:
type SimpColor is (Red, Green, Yellow)
type BuncColor is (Red, Green, Blue)
Литерал перечисления – это
-
Идентификатор
-
Символ
Пример.
type LatinAlphabet(‘A’, ‘B’, ‘C, …, ‘Z’);
Заметим, что тут задается и перечисление, и порядок. Кстати, таким образом можно вводить новые charsetы.
type AsinLatin(‘A’, …, ‘Z’, …, ‘a’, ‘b’, …, ‘z’, …);
Когда язык Ада появился, то Юникода еще не было, а с появлением Юникода для него завели отдельный специальный перечислимый тип.Кстати, проблема перекрытия имен это по сути та же перегрузка(которая естьь во всех основных современных ЯП, кроме Си и Оберона, правда, для фнкций и операторов). Таким образом, можно считать, что перечисление – это одноименная функция, возвращающая соответсвующие значения имени итерала перечисления.
НО: В Ада допустима еще и перегрузка процедур и функций.
Характеристики
Тип файла документ
Документы такого типа открываются такими программами, как Microsoft Office Word на компьютерах Windows, Apple Pages на компьютерах Mac, Open Office - бесплатная альтернатива на различных платформах, в том числе Linux. Наиболее простым и современным решением будут Google документы, так как открываются онлайн без скачивания прямо в браузере на любой платформе. Существуют российские качественные аналоги, например от Яндекса.
Будьте внимательны на мобильных устройствах, так как там используются упрощённый функционал даже в официальном приложении от Microsoft, поэтому для просмотра скачивайте PDF-версию. А если нужно редактировать файл, то используйте оригинальный файл.
Файлы такого типа обычно разбиты на страницы, а текст может быть форматированным (жирный, курсив, выбор шрифта, таблицы и т.п.), а также в него можно добавлять изображения. Формат идеально подходит для рефератов, докладов и РПЗ курсовых проектов, которые необходимо распечатать. Кстати перед печатью также сохраняйте файл в PDF, так как принтер может начудить со шрифтами.