Итак, запомнив, что у проблемы два аспекта - прогноз (описа­ние) и контроль (проверка допустимости поведения данных), пои­щем другие решения.

Отметим, что по отношению к ЯП мы сейчас колеблемся между технологической и авторской позициями, задевая семиотическую.

Второй вариант: структурная совместимость типов. Воспользуем­ся принципом обозначения повторяющегося. Заметили, что часто приходится иметь дело с перечнями атрибутов? Значит, нужно обоз­начить повторяющийся перечень некоторым именем и упоминать это имя вместо самого перечня. Следовательно, нужен языковый конст­рукт для объявления таких имен.

Естественно считать, что имя обозначает не только сам перечень атрибутов, но и класс данных, обладающих объявленными характе­ристиками. Мы пришли к понятию типа данных как класса объек­тов-данных, обладающих известными атрибутами. А искомый языко­вой конструкт - это объявление типа данных. Его назначение - свя­зывать объявляемое имя с указанным перечнем атрибутов данных. Подчеркнем, что основой классификации данных остается перечень характеристик-атрибутов, а имя типа лишь обозначает соответству­ющий перечень.

Теперь, чтобы характеризовать данное, не нужно умалчивать ат­рибуты, как в ПЛ/1, можно коротко и ясно обозначать их одним именем. Кажется, совсем просто, но это шаг от ПЛ/1 к Алголу-68, в котором очень близкая к изложенной концепция типа данных.

С проблемой прогнозирования мы справились, а как с проблемой контроля? По-прежнему нужно сравнивать перечни атрибутов. Дру­гими словами, здесь мы никак не продвинулись. Как справиться с проблемой? Ведь для контроля поведения данных (например, конт­роля совместимости аргументов с параметрами) недостаточно знать имена типов: если имена совпадают, все ясно, а вот когда не совпа­дают, нужно проверять совместимость характеристик типов.

НЕ нашли? Не то? Что вы ищете?

Проблема структурной совместимости типов (иногда говорят, проблема структурной эквивалентности типов, потому что простей­шее правило совместимости - эквивалентность атрибутов) в общем случае очень сложна, может оказаться даже алгоритмически неразрешимой.

Дело в том, что как только возникают имена типов, естественно их применять и в перечнях атрибутов. Например, при определении комбинированного типа указывают­ся типы полей, при определении процедурного типа - типы параметров процедуры и т. п. Но в таком случае имя типа может оказаться связанным уже не с единственным перечнем атрибутов, а с классом таких перечней (возможно, бесконечным, например, описывающим свойства рекурсивных структур-списков). Другими словами, допусти­мые для каждого типа перечни атрибутов определяются, например, контекстно-сво­бодной грамматикой (БНФ). Так что проблема эквивалентности типов сводится к проблеме эквивалентности контекстно-свободных грамматик, которая в общем случае алгоритмически неразрешима.

Третий вариант: именная совместимость типов. Поистине бле­стящее решение состоит в том, чтобы полностью избавиться от про­блемы структурной совместимости, "чуть-чуть" подправив концеп­цию типа, сделав центральным понятием не атрибуты, а имя типа. При этом типы с разными именами считаются разными и в общем случае несовместимыми (если программист не ввел соответствующих операций преобразования типов). Другими словами, забота о содер­жательной совместимости характеристик объектов полностью пере­кладывается на программиста, определяющего типы (что вполне ес­тественно). Если теперь потребовать, чтобы каждый объект данных был связан ровно с одним типом, то и прогнозировать, и проверять - одно удовольствие! Нужно сказать, что объект будет вести себя так-то, обозначаем стиль (характер) его поведения именем типа из име­ющегося набора типов. Нет подходящего - объявляем новый. Нужно проверить совместимость, сравниваем имена типов. Просто, ясно и быстро.

Но наше "чуть-чуть" - в историческом плане шаг от Алгола-68 с его структурной совместимостью типов к Аде с ее именной совмести­мостью через Паскаль, где именная совместимость принята для всех типов, кроме диапазонов (для них действует структурная совмести­мость).

4.2.3. Строгая типизация и уникальность типа

Априорная несовместимость типов, названных разными именами, вместе с идеей "каждому объекту данных - ровно один тип" образу­ют концепцию типа, которую мы назовем концепцией уникальности типа (или просто уникальностью типа). Это ключевая концепция аппарата типов в Аде. Сформулируем правила (аксиомы) уникаль­ности типа:

1.  Каждому объекту данных сопоставлен один и только один тип.

2.  Каждому типу сопоставлено одно и только одно имя (явное или неявное). Типы с неявными именами называются анонимными, и все считаются различными.

3.  При объявлении каждой операции должны быть явно указа­ны (специфицированы) имена типов формальных параметров (и результата, если он есть).

4.  Различные типы априорно считаются несовместимыми по присваиванию и любым другим операциям.

Очень близкая концепция в литературе часто называется строгой типизацией [26], а ЯП с такой концепцией типа - строго типизиро­ванными. От уникальности типа строгая типизация отличается воз­можным ослаблением четвертой аксиомы. Поэтому мы ввели специ­альный термин "уникальность типа" для "совсем строгой" типиза­ции.

4.2.4. Критичные проблемы, связанные с типами

Остался маленький вопрос. Прогнозировать - легко, проверять - легко. А легко ли программировать? Как увязать несовместимость типов, обозначенных разными именами, с естественным желанием иметь операции, применимые к объектам разных типов (полиморф­ные операции). Ведь если связать с формальным параметром опера­ции некоторый тип, то к объектам других типов эта операция ока­жется неприменимой.

Назовем отмеченную проблему проблемой полиморфизма опера­ций. Напомним, что полиморфизм операций широко распространен в математике, жизни, программировании. Операция "+" применима к целым числам, вещественным числам, матрицам, комплексным числам, метрам, секундам и т. п.

Проблема полиморфизма возникла, как только мы взглянули на уникальность типа со стороны операций. Но неприятности поджида­ют нас и со стороны данных. Вполне естественны ситуации, когда в процессе работы программы один и тот же объект выступает в раз­ных ролях, обладает различными характеристиками. Например, чис­ло яблок может превратиться в число людей, взявших по яблоку; буфер, работавший в режиме очереди, может начать функциониро­вать в режиме стека; у массива может измениться размерность и т. п.

Каким должен быть единственный (уникальный) тип такого объ­екта? Если он отражает сразу много ролей, то не придем ли мы к отсутствию контроля (ведь пока буфер работает как очередь, к нему нужно запретить обращаться как к стеку и наоборот)? Если же толь­ко одну роль, то как ему попасть в другую (ведь разные типы апри­орно несовместимы)? Назовем выделенную проблему янус-проблемой (объект ведет себя, как двуликий Янус, даже "многоликий").

4.2.5. Критичные потребности и критичные языковые проблемы

Несколько драматизируем ситуацию и временно представим, что найти решение проблемы полиморфизма не удалось. И вот мы в ро­ли программиста, который старается следовать хорошему стилю со­здания программ.

Допустим, что к его услугам тип "целый", тип "комплексный", тип "матрица". Ему нужно предоставить пользователю возможность складывать объекты любого из названных типов. Хороший стиль программирования требует ввести операционную абстракцию, позво­ляющую пользователю игнорировать несущественные детали (в дан­ном случае - особенности каждого из трех типов данных) и действо­вать независимо от них. Попросту говоря, нужно ввести единую (по­лиморфную) операцию сложения. Если такой возможности ЯП не предоставит, то у программиста может оказаться единственный разумный вариант - избегать пользоваться таким ЯП. Аналогичным ситуациям нет числа. Например, есть возможность рассчитать по­требности взвода, роты, батальона, полка. Требуется ввести абстрак­цию - "рассчитать потребности подразделения" и т. п.

Мы пришли к понятию критичной технологической потребности. Технологическая потребность называется критичной для ЯП в неко­торой ПО, если язык не может выжить в этой ПО без средств удовлетворения этой потребности. Проблему удовлетворения кри­тичной потребности назовем критичной языковой проблемой.

4.2.6. Проблема полиморфизма

Допустим, что критичность проблемы полиморфизма для Ады осознана. Как же ее решать?

По-видимому, самым естественным было бы ввести "объединяющий" тип (например, "операнд_сложения" или "боевое_подразделение"), частными случаями которого были бы исходные типы. И оп­ределить нужную операцию для объединяющего типа. Но что значит "частными случаями"? Ведь в соответствии с концепцией уникаль­ности каждый объект принадлежит только одному типу. Если это "взвод", то не "боевое_подразделение"! Так что в чистом виде эта идея не проходит.

Нечто подобное можно реализовать с помощью так называемых ВАРИАНТНЫХ типов, но каждый вариант должен быть выделен соответствующим значением дискри­минанта, причем заботиться об этом должен пользователь такой "квазиполиморфной" операции. Поэтому такое решение можно рассматривать лишь как суррогат.

Вот если бы к услугам программиста уже был тип "боевое_подразделение", а ему понадобилось ввести новые операции именно для взводов, то (при условии, что у объектов "боевое_подразделение" есть поле "вид") можно было бы объявить, например,

type Т - взвод is new боевое_подразделение (вид => взвод);

Теперь "взвод" - это уже знакомый нам ПРОИЗВОДНЫЙ тип с РОДИТЕЛЬСКИМ типом боевое_подразделение. К его объектам применимы все операции, применимые к боевому_подразделению. Но можно теперь объявить новые операции, применимые только к "взводам", т. е. к "боевым_подразделениям", в поле "вид" которых - значение "взвод". Итак, это решение проблемы полиморфизма "сверху вниз", т. е. нужно заранее предусмотреть частные случаи нужного типа.

Основной вариант решения проблемы полиморфизма, предлагае­мый Адой, это так называемое ПЕРЕКРЫТИЕ операций. Идея со­стоит в том, что связь между вызовом операции и ее объявлением устанавливается не по одному только имени операции, а по так на­зываемому "профилю" (имени операции с учетом типов операндов, типа ре­зультата и даже имен формальных параметров (если вызов по клю­чу)). Другими словами, идея перекрытия в том, что денотат знака определяется не по самому знаку, а с привлечением его ограничен­ного контекста.

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24