|
| |||||||||||||||||||||
| |||||||||||||||||||||
|
[Назад] [Оглавление] [Вперед] 4.2 Основы будущих систем баз данныхВ качестве названия этого раздела была выбрана часть названия второго издания книги Дейта и Дарвена “Основы будущих систем баз данных: третий манифест” [20]. Этот выбор названия раздела не случаен, потому что раздел базируется на этой книге – она для него означает примерно то же, что книги [5] и [13] для подразделов 2.2 и 3.2 соответственно. Прежде, чем переходить к основному материалу раздела, кратко представим содержание книги [20]. Прежде всего, заметим, что это второе издание, вышедшее в свет в 2000 г. Первое издание было опубликовано в 1998 г. под названием “Основы объектно/реляционных баз данных” [19]. Вот что пишут Д&Д по поводу изменения названия в предисловии ко второму изданию [20]: “Название первой редакции характеризовало Манифест как “основание объектно/реляционных баз данных”. Хотя эта характеристика была точной, она не была достаточной. Теперь мы считаем Манифест (как, впрочем, было всегда) основанием будущих баз данных вообще – включая, например, базы данных, содержащие темпоральные данные, и базы данных, используемые в связи с World Wide Wed .” Однако, как кажется, более вероятными причинами для смены названия были следующие обстоятельства:
Конечно, второе издание [20] появилось так скоро после выхода в свет первого издания не только и не столько потому, что авторы решили изменить название. В первом издании была недостаточно доработана часть книги, посвященная наследованию типов. За два года после выхода в свет этого издания Д&Д сумели построить законченную модель наследования, и именно желание представить полный вариант своих предложений побудило авторов к быстрым подготовке и публикации второго издания книги. Второе издание [20] имеет следующую структуру. Основной текст книги разделен на четыре части: вступление, формальные спецификации, неформальные обсуждения и объяснения, подтипизация и наследование. Первая часть книги состоит из двух вводных глав, написанных без привлечения каких-либо формализмов. В главе 1 содержится базовая информация, поясняющая некоторые основополагающие идеи, лежащие в основе книги. В частности, обсуждаются ключевые логические различия между понятиями м одели и реализации; значения и переменной; значения, вида и кодировки значения. Глава 2 состоит из неформального обсуждения двух возможных подходов к ключевому вопросу интеграции объектов и отношений (что соответствует понятию объектного класса в реляционной модели данных?). Демонстрируется, что один из этих подходов является правильным, а другой – ложным. Вторая часть книги носит наиболее формальный характер. В главе 3 приводится сам Третий манифест в том виде, как мы изложили его в подразделе 4.1. В главе 3 содержится определение новой реляционной алгебры (“A ”). В главе 4 определяется язык Tutorial D . Этот язык основывается на принципах, заложенных в Манифесте, и на алгебре A . Tutorial D служит основой для примеров в следующих главах книги. Он также позволяет судить о том, что могла бы представлять собой на практике СУБД, поддерживающая идеи Манифеста. Третья часть представляет собой реальную сердцевину книги. Она состоит из шести глав, по одной для каждого из шести разделов Манифеста, как он определяется в главе 3. Эта часть, по существу, является сильно расширенным вариантом неформальных комментариев к предписаниям, запретам и очень строгим суждениям Третьего манифеста Четвертая часть книги играет для подтипизации и наследования ту же роль, что первые три части . Так, глава 12 соответствует первой части (она содержит общее введение в тему ); глава 13 соответствует второй части (она содержит формальные определения); а главы 14, 15 и 16 соответствуют третьей части (они содержат расширенные, но неформальные пояснения и обсуждения этих формальных определений). Точнее, в главе 14 рассматривается только одиночное наследование при наличии скалярных типов; в главе 15 идеи, обсуждаемые в главе 14, расширяются для включения поддержки множественного наследования; в главе 16 в расчет принимаются также типы кортежей и отношений. В дополнение к перечисленным главам в книге содержится одиннадцать приложений.
В этом подразделе мы остановимся на следующих темах, обсуждаемых в книге [20]:
Общие принципыЗдесь мы опираемся на материал первых двух глав [20]. Назначение материала состоит в том, чтобы ввести некоторую концептуальную базу для дальнейшего изложения. Логические различия и логические ошибки, концептуальная целостностьНаиболее важным принципом, которым руководствовались Д&Д на протяжении своей работы над Третьим Манифестом, является следующий: все логические различия являются большими различиями. Основой любой формальной системы является логика. Поэтому во всем, что относится к формальным системам вообще и что касается Манифеста в частности, различия, которые по своей природе являются логическими, очень важны, и на них следует обращать особое внимание. Из этой максимы следует, что все логические ошибки являются большими ошибками. Принцип концептуальной целостности, который Д&Дтакже относят к числу основополагающих, трактуется в том смысле, что с целью поддержания интеграции концепций необходимо поставить некоторые концепции на первое место. Рассматриваемые концепции должны быть тщательно отобраны, их должно быть как можно меньше, они должны быть согласованы и приемлемы по своей природе. Некоторые ключевые логические различияСуществуют некоторые логические различия, которые имеют отношение ко всему дальнейшему – это различия между (a) моделью и реализацией, (b) значением и переменной, и (c) значением, видом и кодировкой. Различие между моделью и реализацией определяется следующим образом:
Различие между моделью и реализацией в действительности является важным частным случаем различия между логическим и физическим аспектами системы. Во всем Манифесте и во всей книге Д&Д имеют дело с абстрактной моделью, а не с вопросами реализации. (Под “реализацией” понимается реализация СУБД, а не некоторого приложения, работающего под управлением этой системы.) Второе логическое различие – это различие между значениями и переменными (под переменной мы понимаем переменную в обычном смысле языка программирования). Используются следующие определения:
Значения могут быть произвольно сложными; например, значение может быть массивом, стеком, списком, отношением, геометрической точкой и т.д. Аналогичное замечание относятся и к переменным. Третье логическое различие – это различие между собственно значением и видом этого значения в определенном контексте (например, в качестве текущего значения некоторой переменной). Одно и то же значение может одновременно проявляться в нескольких разных видах. Каждый из этих видов внутренним образом состоит из некоторой кодировки, или физического представления значения, и эти кодировки не обязательно одинаковы. Например, во множестве целых чисел целое значение 3 встречается ровно один раз, но любое число переменных одновременно может содержать виды этого целого числа в качестве своего текущего значения. Некоторые из этих видов могли бы быть физически представлены посредством, например, десятичной системы кодирования, а другие – на основе двоичной системы. Поэтому существует логическое различие между видом значения и кодировкой, которая применяется для внутреннего представления. Следует заметить, что “вид значения” является концепцией модели, а “кодировка вида” относится к концепциям реализации. Например, пользователям может понадобиться знать, содержат ли две различные переменные виды одного и того же значения, но им не должно требоваться знать, используется ли для этих двух видов одно и то же физическое кодирование. Типы данных и объектные классыЧтобы иметь возможность детально обсуждать соотношение между объектной и реляционной технологиями, необходимо разобраться в том, какая концепция в реляционном мире является двойником концепции объектного класса в объектном мире.114 Этот вопрос исключительно важен, поскольку объектный класс является фундаментальной концепцией объектного мира, и все остальные объектные понятия в большей или меньшей степени зависят от этой концепции. В качестве ответа на поставленный выше вопрос возможны два ответа: (a ) концепции объектного класса соответствует концепция домена; (b ) концепции объектного класса соответствует концепция отношения (вернее, переменной отношения, relvar ). Д&Д доказывают, что верен только первый ответ. При этом в качестве аксиомы принимается то, что требуется оставаться в классической реляционной среде. Для начала требуется навести должный порядок в реляционной терминологии. Как следует из классических определений реляционной модели данных, каждое отношение состоит из двух частей, заголовка и тела, где заголовок – это множество пар имя-столбца:имя-домена, Предлагается следующий способ
понимания природы отношений: Для заданного отношения R
заголовок R обозначает некоторый предикат (истинностную функцию), а
каждая строка тела R – это некоторое истинное высказывание, получаемое из предиката путем подстановки
некоторых значений доменов вместо заменителей или параметров этого предиката
(“инстанциация предиката”). Для примера рассмотрим отношение MMQ (“ведомость материалов”) (рис. 3.1).
Рис. 3.1. Пример отношения ведомости материалов MMQ (в заголовке показаны имена атрибутов и доменов) Заголовку отношения MMQ соответствует “деталь MAJOR _ P # содержит QTY деталей MINOR _ P # ”. Следующие высказывания являются истинными: “деталь P 1 содержит 5 деталей P 2 ” (получено подстановкой значений доменов P 1 , 5 и P 2 ); “деталь P 1 содержит 3 детали P 3” (получено подстановкой доменных значений P1 , 3 и P3 ) и т.д. Другими словами, домены состоят из вещей, о которых мы говорим; отношения состоят из истин, которые мы изрекаем по поводу этих вещей. Из этого следует, что ( a ) необходимы и домены, и отношения (без доменов не о чем говорить, без отношений нельзя ничего сказать); ( b ) домены и отношения – это не одно и то же; домены и отношения достаточны, равно как и необходимы; с логической точки зрения больше ничего не требуется. Когда люди говорят об отношениях, они очень часто имеют в виду переменные отношений, а не сами отношения. В действительности это частный случай логического различия между значениями и переменными. Например, значение данного отношения (множество строк) не меняется во времени, а значение переменной этого отношения меняется. Замечая, что подобно отношению и в отличие от переменной отношения значение данного домена (множество скаляров) также не меняется во времени, можно придти к ложному заключению, что домены и отношения являются вещами одного и того же вида. И наконец, смешение понятий собственно отношений и переменных отношений, приводит к тому (еще большему) заблуждению, что домены и переменные отношений – это одно и то же. Для достижения предельной ясности Д&Д вводят явный термин relvar как сокращенную форму от relation variable (переменная отношения) и высказываются в терминах relvars, а не отношений, когда имеются в виду действительно переменные отношения. Теперь можно обсудить то соотношение понятий, которое Д&Д считают правильным – концепция домена соответствует концепции объектного класса. Обычно считается, что домен – это всего лишь концептуальный пул значений, из которого берутся реальные значения столбцов отношений. Такое понимание является удовлетворительным только до поры до времени. В действительности, домен – это то же самое, что тип данных – определенный в системе или определенный пользователем тип. Поэтому эти термины являются взаимозаменяемыми. С понятием типа данных ассоциируется понятие операций, которые допускается применять к значениям этого типа (со значениями типа можно работать только посредством применения операций, определенных для этого типа). Различаются собственно тип (или домен) и внутреннее представление,или физическая кодировка значений этого типа внутри системы. Например, номера деталей могли бы быть представлены внутренним образом как строки символов, но отсюда не следует, что можно производить операции с номерами деталей как со строками символов. Операции, определяемые для данного типа, зависят от предполагаемого смысла или семантики этого типа, а не от способа представления значений типа в системе. Внутренние представления значений типа должны быть скрыты от пользователя. Подобная строгая типизация в понимании Д&Д означает, что (a) у каждого значения имеется тип и (b) при попытке выполнения любой операции система проверяет, что операнды имеют типы, допустимые для этой операции. В реляционной модели нет ничего, для чего требовалось бы ограничить типы данных только простыми формами. Единственным требованием является то, что значениями домена можно манипулировать только посредством определенных для него операций; внутреннее представление должно быть скрыто. Другими словами, вопрос о том, какие поддерживаются типы данных, ортогонален вопросу поддержки реляционной модели. Итак, в реляционном мире домен – это тип данных, определяемый системой или пользователем, значениями которого можно манипулировать только с помощью определенных для него операций (и внутреннее представление которого может быть произвольно сложным, но скрытым от пользователя). Если обратиться к объектному миру, выясняется, что самое фундаментальное среди всех понятий, объектный класс, это тип данных, определенный системой или пользователем, значениями которого можно манипулировать исключительно посредством операторов, определенных для этого типа (и внутреннее представление которого может быть сколь угодно сложным, но скрытым от пользователя). Другими словами, домены и объектные классы – это одно и то же; это обеспечивает ключ к интеграции двух технологий, и именно эта позиция отстаивается в Третьем Манифесте. Уравнивание объектного класса с relvar является серьезной логической ошибкой. По мнению Д&Д истоки этой ошибки кроятся в синтаксической близости определений класса и переменной отношения. Принципиальное различие понятий заключается в том, что relvar – это переменная, а класс – это тип. (Переменная отношения и домен - это не одно и то же.) Это уже показывает ошибочность уравнивания объектного класса с relvar . Более подробный анализ позволяет придти к выводу, что принятие второго вида уравнивания понятий подрывает концептуальную целостность реляционной модели. РезюмеВ объектной технологии имеется одна безусловно хорошая идея – определяемые пользователями типы (включая определяемые пользователями операции). Одна идея является вероятно хорошей – наследование типа (хотя не здесь судить, насколько именно хорошей ). Ключевой технической идеей Третьего Манифеста является то, что эти две идеи полностью ортогональны реляционной модели. Чтобы достичь желательной объектной функциональности, не надо абсолютно ничего делать с реляционной моделью. Пользователям требуются истинно реляционные СУБД (“истинно реляционные системы” не означают SQL-ориентированные системы), в которых содержится должная поддержка доменов, и тогда они получат “объектно/реляционные” СУБД, которых добивались. Привлекательность собственно объектных СУБД (в противоположность “объектно/реляционным” СУБД) можно целиком объяснить частичной неудачей существующих поставщиков SQL-ориентированных систем в части должной поддержки реляционной модели. Но это не является аргументом для отказа от реляционной модели. Система типовЗдесь мы кратко обсудим основные положения [20], связанные с построением системы типов, собрав воедино развернутые комментарии Д&Д к разным предписаниям, запретам и очень строгие суждения Третьего манифеста. Скалярные типыТермин тип охватывает и скалярные и не скалярные типы. Между скалярными и не скалярными типами имеется принципиальное различие. Скалярные типы вне зависимости от уровня сложности их реальных представлений – не содержат компонентов, видимых для пользователя.115 Напротив, не скалярные типы содержат видимые для пользователя компоненты; в частности, типы кортежей и отношений не являются скалярными и содержат наборы видимых для пользователя атрибутов.
Значения некоторого скалярного типа обобщенно называются скалярными значениями (для краткости, скалярами). Аналогично, переменные, значения которых ограничиваются скалярами, обобщенно называются скалярными переменными. Реальное представление таких значений и переменных может быть сколь угодно сложным. Скалярные типы могут определяться пользователями либо быть системно-определенными (“встроенными”). Требуется, чтобы поддерживался хотя бы один встроенный скалярный тип – тип истинностного значения. Для определенности предполагается, что для этого типа поддерживаются операции NOT , AND и OR и литералы TRUE и FALSE . Для удобства считается, что поддерживаются также встроенные скалярные типы INTEGER , RATIONAL (Д&Д предпочитают использовать этот термин вместо REAL ) и CHAR с соответствующими операциями и литералами. Вот несколько примеров определений пользовательских скалярных типов (используется синтаксис Tutorial D , который в данном случае не требует пояснений). TYPE S# POSSREP { CHAR } ; Здесь у типа S # имеется только одно объявленное возможное представление (“POSSREP ”), обладающее именем S # по умолчанию.116У этого возможного представления имеется ровно один компонент, имя которого по умолчанию совпадает с именем возможного представления, т.е. опять S # . Поскольку этот компонент определяется как принадлежащий типу CHAR , и не указано какое-либо дополнительное ограничение для типа S # , множество допустимых значений этого типа является множеством всех значений, которые можно представить в виде символьных строк. Тип QTY определяется аналогичным образом, но для него указано дополнительное ограничение – значения этого типа должны быть положительными. Вот несколько более сложных примеров определения скалярных типов: TYPE LENGHT POSSREP { L RATIONAL } ; TYPE POINT TYPE POLYGON Определение типаLENGTH аналогично ранее приведенным определениям типов за исключением того, что единственному компоненту возможного представления этого типа задано явное имя L . ТипPOINT (“точка”) отличается от предыдущих примеров тем, что у него есть два различных объявленных возможных представления: первое –POINT (у этого возможного представления то же имя, что и у типа), с компонентами (Декартовыми координатами) X и Y , и второе – POLAR с компонентами (полярными координатами)R и THETA . Только в тех случаях, когда заданный тип имеет два или более объявленных возможных представлений, необходимо давать таким возможным представлениям явные имена. ТипELLIPSE (“эллипс”) отличается от предыдущих примеров тем, что его объявленное возможное представление основано не на встроенных, а на определенных пользователем типахLENGTH и POINT . Наконец, типPOLYGON (“многоугольник”) отличается от предыдущих примеров тем, что единственный компонент его объявленного возможного представления VERTICES принимает значения-отношения. То есть многоугольник представлялся бы отношением, содержащим по одному кортежу для каждой вершины этого многоугольника; этот кортеж содержал бы номер вершины (значение типаINTEGER ) вместе с самой соответствующей вершиной (значение типа POINT ). Следует подчеркнуть, что операция определения типа реально не создает соответствующего множества значений. Концептуально, это множество значений уже существует и всегда будет существовать. Все, что делает операция “определения типа”, заключается в введении имени, посредством которого можно ссылаться на это множество значений. Из RM -предписания 2 следует, что любое значение всегда относится к одному и только одному типу (если не поддерживается наследование). Побочным (но важным) следствием является то, что пересечение множеств значений любых двух различных типов всегда пусто (опять же при отсутствии наследования). Скалярная операция – это операция, возвращающая скалярное значение или обновляющая скалярную переменную. 117 Как и скалярные типы, скалярные операции могут определяться либо пользователями, либо системой (“встраиваться”). Встроенные операции определяются только в связи со встроенными типами. Предполагается, что для встроенных скалярных типов BOOLEAN , INTEGER , RATIONAL и CHAR поддерживается естественный для этих типов набор операций, причем имена некоторых операций перегружены. Определяемые пользователями операции можно определять как для встроенных типов, так и для определяемых пользователями. Факт существования операции с заданным именем не препятствует возможности перегрузки – то есть определения другой операции с тем же именем, но с другими объявленными типами параметров и (возможно) результатов, и следовательно, по крайней мере, частично отличной семантикой. Можно было бы даже не только перегрузить, но и переопределить существующую операцию посредством определения другой операции с тем же именем и теми же объявленными типами параметров и результатов, но с другой семантикой. По очевидным соображениям, мы рекомендуем, чтобы это средство использовалось со всеми возможными предосторожностями. Вот пример определяемой пользователем скалярной операции, работающей со встроенным типом: OPERATOR
ABS ( N RATIONAL ) RETURNS RATIONAL ; Операция ABS определяется с единственным параметром N объявленного типа RATIONAL и возвращает результат того же объявленного типа. Это операция только чтения, что означает, что ни при каком вызове функция не пытается обновлять свой собственный аргумент. Вот другой пример определяемой пользователем скалярной операции только чтения, которая работает с некоторыми определяемыми пользователем типами: OPERATOR
DIST ( P1 POINT, P2 POINT ) RETURNS LENGTH ; Эта операция, DIST (“расстояние”) определяется с двумя параметров P 1 и P 2 объявленного типа POINT , и возвращает результат объявленного типа LENGTH . Операции THE _ X и THE _ Y используются для получения координат X и Y двух рассматриваемых точек, затем эти координаты используются для получения требуемого расстояния. WITH позволяет ввести сокращения для некоторых выражений. Для определенности принимается, что аргументы вызовов операций задаются в позиционной нотации, т.е. в данном вызове i -й аргумент в списке аргументов соответствует i -му параметру в списке параметров определения операции. Вот пример операции обновления: OPERATOR
REFLECT ( P POINT ) UPDATES P ; Операция REFLECT фактически перемещает точку с декартовыми координатами (x ,y ) в центрально-симметричную точку (- x ,- y ). Операция определяется с одним параметром P объявленного типа POINT и при вызове должным образом обновляет аргумент, соответствующий этому параметру. Как в предыдущем примере, операции THE _ X и THE _ Y используются для “чтения” координат X и Y заданной точки; псевдопеременныеTHE _ X и THE _ Y используются для обновления этих координат. Вызов REFLECT не возвращает результата; такой вызов не имеет значения и не является скалярным выражением. Поэтому вызов должен выполняться посредством явного оператора CALL (или некоторого его логического эквивалента). По поводу приведенных примеров следует сделать несколько замечаний:
Как отмечалось ранее, в определении любого скалярного типа должно указываться по крайней мере одно объявленное возможное представление для значений этого скалярного типа (и при таком заданном скалярном типе T и таком возможном представлении PR каждое значение типа T должно быть представимо посредством PR ).118Объявление возможного представления автоматически приводит в действие поддержку соответствующего селектора (и нельзя обеспечить селекторы никаким другим способом). Следовательно, селекторы и возможные представления находятся во взаимно однозначном соответствии друг с другом (параметры селекторов и компоненты возможных представлений находятся также во взаимно однозначном соответствии). Поэтому можно принять соглашение о задании селектору и соответствующему возможному представлению одного и того же имени (хотя они являются логически различными понятиями). Следует подчеркнуть различия между вызовами селекторов вообще и литералами в частности. Коротко говоря, все литералы являются вызовами селекторов, но не все вызовы селекторов являются литералами. Вызов селектора является литералом тогда и только тогда, когда его аргументы (если они есть) в свою очередь являются литералами. Таким образом, литерал является символом, который обозначает некоторое фиксированное значение, которое определяется на все времена конкретным рассматриваемым символом. Объявленный тип этого символа (который является, конечно, частным случаем выражения) также определяется самим. Вернемся к примеру определяемого пользователем типа POINT , чтобы обсудить вопросы определения и реализации типов. Повторим в упрощенном виде определение этого типа: TYPE POINT В данном примере в определении типаспецифицированы два объявленных возможных представления – POINT и POLAR . Следовательно, будут существовать две соответствующие операции выбора: POINT , которая позволяет пользователю задавать декартовы координаты X и Y как два значения типа LENGTH и возвращает соответствующее значение типа POINT , и POLAR , которая позволяет пользователю задавать полярные координаты R и THETA как значения типов LENGTH и ANGLE соответственно и возвращает соответствующее значение типа POINT .
OPERATOR
POINT ( X LENGTH, Y LENGTH ) RETURNS POINT ; “Высоко защищенные операции, не входящие в D ” представлены в приведенном коде посредством точечной нотации. Селектор POLAR также мог бы быть реализован “вне среды D ” (снова псевдокод): OPERATOR POLAR ( R LENGTH, THETA ANGLE ) RETURNS POINT ; Но селектор POLAR , возможно, менее эффективно мог бы быть реализован в терминах селектора POINT : OPERATOR POLAR ( R LENGTH, THETA ANGLE ) RETURNS POINT ; Из всего этого следует, что реализаторы типа(но не определители типа и, конечно, не пользователи типа) должны на самом деле знать реальные представления. Пусть PR - это возможное представление скалярного типа T , и пусть у PR имеются компоненты C 1 , C 2 , …, Cn . Определим THE _ C 1 , THE _ C 2 , …, THE _ Cn как семейство операций, таких что для каждогоi (i = 1, 2, …, n ), операция THE _ Ci обладает следующими свойствами:
Несколько примеров : TYPE TEMPERATURE POSSREP CELSIUS { C RATIONAL } ; VAR TEMP TEMPERATURE ; CEL
:= THE_C ( TEMP ) ; В первом присваивании температура, измеренная в градусах Цельсия, которая является текущим значением переменной TEMP типа TEMPERATURE , присваивается переменной CEL типа RATIONAL ; во втором – текущее значение переменной CEL типа RATIONAL , рассматриваемое как температура в градусах Цельсия, используется для обновления переменной TEMP типа TEMPERATURE . Операция THE _ C фактически раскрывает возможное представление температуры посредством “градусов Цельсия” как для целей обновления, так и для целей только чтения. Но это возможное представление не обязательно является реальным представлением; например, температуру можно было бы представлять в градусах Фаренгейта, а не в градусах Цельсия. Вот немного более сложный пример: TYPE POINT POSSREP POINT { X LENGTH, Y LENGTH } ; VAR L LEHGTH ; L
:= THE_X ( P ) ; В первом присваивании переменной L типа LEHGTH присваивается координата X точки, являющейся текущим значением переменной P типа POINT ; во втором – текущее значение переменной L типа LEHGTH используется для обновления координаты X переменной P типа POINT . Операции THE _ X и THE _ Y фактически раскрывают возможное представление точек посредством “Декартовых координат” как для целей обновления, так и для целей только чтения; и снова это возможное представление не обязательно совпадает с реальным представлением.
Заметим теперь, что псевдопеременные THE _ логически необязательны. Рассмотрим второе присваивание в первом примере. Это присваивание, в котором используется псевдопеременная, логически эквивалентно другому, в котором псевдопеременная не используется: TEMP := CELSIUS ( CEL ) ; /* вызов селектора CELSIUS */ Вот логический эквивалент второго присваивания во втором примере без использования псевдопеременной: P := POINT ( L, THE_Y ( P ) ) ; /* вызов селектора POINT */ Другими словами, псевдопеременные как таковые не являются строго
необходимыми для поддержки обсуждаемой разновидности обновления на уровне
компонентов. Однако подход с использованием псевдопеременных интуитивно
выглядит более привлекательным, чем альтернативный (для которого первый подходможно рассматривать как сокращенную форму); более
того, он также обеспечивает высокую степень устойчивости к изменениям
синтаксиса соответствующего селектора. Заметим также, что по поводу реализации операций раскрытия возможного представления можно сделать замечания, аналогичные тем, которые приводились выше в связи с операциями выбора значений скалярного типа. Типы кортежей и отношенийКортежные типы и типы отношений являются генерируемыми типами, получаемыми путем применения генераторов типа TUPLE и RELATION соответственно. Вот пример использования кортежного типа: VAR ADDR TUPLE { STREET CHAR, Здесь определяется кортежная переменная ADDR типа TUPLE { STREET CHAR, CITY CHAR, STATE CHAR, ZIP CHAR } Это пример генерируемого (кортежного) типа. Каждая из комбинаций “имя : тип” является атрибутом этого кортежного типа, и множество всех таких атрибутов является заголовком кортежного типа. Мощность этого множества называется степенью кортежного типа. Кортежная переменная ADDR имеет те же самые атрибуты, заголовок и степень, и то же касается всех возможных значений этой переменной. Умышленно не поддерживается отдельная операция “определения типа кортежа”. Одним из оснований для такого решения является то, что иначе потребовалось бы вводить имя кортежного типа (помимо уже существующего имени TUPLE {…}). Такие дополнительные имена усложнили бы другие аспекты предлагаемого Д&Д подхода, например, решения вопроса о том, когда два типа совпадают.119 По этим соображениям предписывается, чтобы кортежные типыиспользовались “в виде подстановки”, как часть операции, которая определяет кортежную переменную отдельно. Для кортежных типов требуется поддержка “операций, аналогичных операциям RENAME , project , EXTEND и JOIN из реляционной алгебры”. Вот несколько примеров, не требующих специальных пояснений (в последнем примере присутствует вызов селектора кортежей – фактически, кортежный литерал): ADDR RENAME ZIP AS POSTCODE /* переименование атрибута кортежа */ ADDR RENAME PREFIX ' ST ' AS ' G ' /* то же самое, префиксный вариант */ ADDR { STATE , ZIP } /* проекция кортежа */ EXTEND ADDR ADD NAME ('Clark Kent') AS NAME /* расширение кортежа */ ADDR JOIN /* соединение кортежей */ Вот пример присваивания кортежей: ADDR := TUPLE {STREET 'One
Jacob Way' , Выражение справа от знака присваивания является другим примером вызова селектора кортежей (конечно, это всего лишь кортежный литерал). Переменная кортежа, указанная в левой части кортежного присваивания, и кортеж, обозначенный кортежным выражением в правой части, должны быть одного и того же кортежного типа, т.е. они должны иметь совпадающие имена атрибутов, и соответствующие атрибуты должны быть в свою очередь одного и того же типа. Следующий пример иллюстрирует обязательную операцию экстракции атрибута, которая выделяет значение указанного атрибута из указанного кортежа: VAR STATE_VAR CHAR ; STATE_VAR := STATE FROM ADDR ; Явно допускается, чтобы кортежи (и отношения) включали атрибуты, значениями которых были бы кортежи. Операции, которые применяются к этим кортежным значениям, это в точности те же операции языка D , которые применяются к кортежным значениям вообще. Вотпример: VAR NADDR1
TUPLE { NAME NAME, Важное преимущество схемы именования типов кортежей, предписанной в Манифесте, состоит в том, что она облегчает задачу вывода типа результата произвольного кортежного выражения. Например, рассмотрим следующее кортежное выражение (проекцию кортежа): NADDR2 { NAME, ZIP } Это конкретное выражение вычисляет кортеж, который порождается из текущего значения NADDR2 путем “проецирования на все, кроме” атрибутовSTREET , CITY и STATE . И кортежный тип этого порожденного кортежа есть в точности TUPLE { NAME NAME, ZIP CHAR } Рассмотрим следующие кортежные типы: TUPLE { NAME NAME, ADDR TUPLE { STREET CHAR, CITY
CHAR, TUPLE { NAME NAME, STREET CHAR, CITY CHAR, Будем называть эти два типа TT 1 и TT 2 соответственно. Пусть теперь NADDR 1 и NADDR 2 являются переменными кортежа типов TT 1 и TT 2 , соответственно. Тогда:
NADDR2 := NADDR1 UNWRAP ADDR ; Все, что говорилось выше по поводу кортежных типов, с небольшими коррективами применимо к типам отношений, и мы не будем повторяться. Остановимся только на двух дополнительных операциях – GROUP и UNGROUP . Рассмотрим следующие типы отношения: RELATION { S# S#, PQ RELATION { P# P#, QTY QTY } … } RELATION { S# S#, P# P#, QTY QTY } Назовем эти два типа отношения RT 1 и RT 2 соответственно. Пусть теперь SPQ 1 и SPQ 2 – это relvar типов RT 1 и RT 2 соответственно. Тогда:
Таким образом, окончательный результат относится к типу RT 2, и поэтому допустимо следующее присваивание: SPQ2 := SPQ1 UNGROUP PQ ; Модель наследованияВ Третьем манифесте представлена хорошо проработанная, концептуально согласованная модель наследования, базирующаяся на концепции специализации путем ограничения. Д&Д сначала разрабатывают теорию одиночного наследования для скалярных типов, затем развивают ее для множественного наследования скалярных типов и, наконец, обобщают до случая множественного наследования типов кортежей и ограничений. В этой статье мы не можем полностью (хотя бы кратко) описать модель. Ограничимся изложением предписаний (IM -предписаний, IM от Inherinence Model ). C имволы T и T' используются далее для обозначения пары типов, таких что T' является подтипом T (или, что эквивалентно, T является супертипом для T'). В общем случае эти типы могут быть не только скалярными. IM-предписание 1T и T' должны быть типами; то есть каждый из них должен быть именованным множеством значений. IM-предписание 2Каждое значение T' должно быть значением T; то есть множество значений, составляющих T', должно быть подмножеством множества значений, составляющих T (другими словами, если значение принадлежит типу T', то оно также должно принадлежать типу T). Более того, если T и T' различны (см. IM-предписания 3 и 4), то должно существовать по крайней мере одно значение, которое принадлежит типу T и не принадлежит типу T'. IM-предписание 3T и T' не обязательно должны быть различны; то есть, каждый тип должен быть как подтипом, так и супертипом самого себя. IM-предписание 4Если и только если типы T и T' различны, то T' является собственным подтипом T, и T является собственным супертипом T'. IM-предписание 5Каждый подтип T' должен быть подтипом T. Каждый супертип T должен быть супертипом T'. IM-предписание 6Если и только если T' является собственным подтипом T и не существует типа, который одновременно является собственным супертипом T' и собственным подтипом T, то T' является непосредственным подтипом T, а T является непосредственным супертипом T'. Тип, который не является непосредственным подтипом какого-либо типа, является корневым типом. Тип, который не является непосредственным супертипом какого-либо типа, является листовым типом. IM-предписание 7( Вариант, предполагающий только одиночное наследование )Если типы T1 и T2 таковы, что ни один из них не является подтипом другого, то они должны быть непересекающимися; то есть никакое значение не должно одновременно принадлежать типу T1 и типу T2. IM-предписание 7’( Вариант, предполагающий множественное наследование )Если типы T1 и T2 являются различными корневыми типами, то они должны быть непересекающимися; то есть никакое значение не должно одновременно принадлежать типу T1 и типу T2. IM-предписание 8( Вариант, предполагающий только одиночное наследование )Пусть значение v принадлежит скалярному типу T. Если и только если не существует собственный подтип T' типа T такой, что vтакжепринадлежит типу T', то T является наиболее конкретным типом (для) v. IM-предписание 8’( Вариант, предполагающий множественное наследование )Для каждого набора скалярных типов T1, T2, …, Tn (n>0) должен иметься общий подтип T' такой, что заданное значение принадлежит каждому из типов T1, T2, …, Tn, если и только если оно принадлежит типу T'. IM-предписание 9Пусть скалярная переменная V относится к объявленному типу T. По причине возможности замены значений (см. IM-предписание 16) значение v, присвоенное V , в любой момент времени может принадлежать любому подтипу T' типа T как своему наиболее конкретному типу. Поэтому можно моделироватьV как именованный упорядоченный триплет вида <DT,MST,v>, где:
Обозначения DT(V), MST(V), v(V) используются для ссылок на компоненты DT, MST и v этой модели скалярной переменной V соответственно. Далее, пусть X - скалярное выражение. Систему обозначений DT(V), MST(V), v(V) можно очевидным образом расширить для ссылок на объявленный тип DT(X), текущий наиболее конкретный тип MST(X) и текущее значение v(X) выражения X соответственно, где “объявленный тип” – это то, что разъяснялось в RM-предписании 3, и этот тип известен во время компиляции, а “текущий наиболее конкретный тип” и “текущее значение” относятся к результату вычисления X и поэтому в общем случае неизвестны до времени выполнения. IM-предписание 10Пусть T - регулярный собственный супертип (см. IM-предписание 20), и пусть T' - непосредственный подтип T. Тогда в определении T' должно специфицироваться ограничение специализации SC, сформулированное в терминах T и такое, что значение типа T должно принадлежать типу T', если и только если оно удовлетворяет ограничению SC. Должно существовать по крайней мере одно значение типа T, которое не удовлетворяет ограничению SC. IM-предписание 11Пусть X - выражение. Рассмотрим присваивание V := X ; (где V является переменной). DT(X) должно быть подтипом DT(V). Присваивание должно сделать MST(V) равным MST(X), а v(V) - равным v(X). IM-предписание 12Рассмотрим сравнение на равенство Y = X (где Y и X являются выражениями). DT(X) и DT(Y) должны иметь общий супертип. Сравнение должно возвращать true, если MST(Y) равно MST(X) и v(Y) равно v(X), иначе - false. IM-предписание 13Пусть rx и ry - отношения с общим атрибутом A, и пусть объявленные типы A в rx и ry - это DT(Ax) и DT(Ay) соответственно. Рассмотрим соединение rx и ry (обязательно по A, по крайней мере, частично). DT(X) и DT(Y) должны иметь общий супертип и, следовательно, обязательно общий наиболее конкретный супертип, скажем T. Тогда объявленным типом A в результате соединения должен быть тип T. Аналогичные замечания относятся к объединению, пересечению и разности операций. То есть в каждом случае:
IM-предписание 14Для каждого типа T должна поддерживаться операция в форме TREAT_DOWN_AS_T ( X ) (или ее логический эквивалент), где X является выражением. T должен быть подтипом DT(X) и MST(X) должен быть подтипом T. Такие операции обобщенно называются операциями “TREAT DOWN”; их семантика такова:
IM-предписание 15( Вариант, предполагающий только одиночное наследование )Для каждого типа T, должна поддерживаться логическая операция вида IS_T ( X ) (или ее логический эквивалент), где X - выражение. DT(X) должен быть супертипом для T. Эта операция должна возвращать true, если v(X) принадлежит типу T, и false в противном случае. IM-предписание 15’( Вариант, предполагающий множественное наследование )Для каждого типа T, должна поддерживаться логическая операция вида IS_T ( X ) (или ее логический эквивалент), где X - выражение. DT(X) и T должны иметь общий подтип. Эта операция должна возвращать true, если v(X) принадлежит типу T, и false в противном случае. IM-предписание 16Пусть Op - операция только чтения, пусть P - параметр Op, и пусть T - объявленный тип для P. Тогда должно допускаться, чтобы объявленный тип выражения аргумента (и следовательно, тем более, наиболее конкретный тип значения аргумента), соответствующего параметру P в вызове Op, был любым подтипом T' типа T. Другими словами, операция только чтения Op применяется к значениям типа T и поэтому, обязательно, к значениям типа T' – Принцип Наследования Операций (Только Чтения). Из этого следует, что такие операции являются полиморфными, поскольку они применимы к значениям нескольких различным типам – Принцип Полиморфизма Операций (Только Чтения). И далее из этого следует, что везде, где допускается значение типа T, должно также допускаться значение любого собственного подтипа T – Принцип Возможности Замены (Значений). IM-предписание 17Для каждой заданной операции Op должны иметься:
Если действительно существует несколько версий Op, то все эти версии фактически должны реализовывать одну и ту же семантику. IM-предписание 18Пусть Op - операция обновления, и пусть P - параметр Op, который не является предметом обновления. Тогда Op должна вести себя как операция только чтения, насколько это относится к P, и, следовательно, все аспекты IM-предписания 16 должны быть применимы. IM-предписание 19Пусть Op - операция обновления, пусть P - параметр Op, который является предметом обновления, и пусть T является объявленным типом для P. Тогда неясно, должно ли допускаться, чтобы объявленный тип (и, следовательно, тем более, текущий наиболее конкретный тип) аргумента-переменной, соответствующего параметру P в некотором вызове Op, был собственным подтипом типа T (в некоторых случаях это должно допускаться, а в некоторых - нет). Из этого следует, что для каждой такой операции обновления Op и для каждого параметра P операции Op, который является предметом обновления, необходимо явно установить, для каких подтипов объявленного типа T параметра P операция Op должна наследоваться – Принцип Наследования Операций (Обновления). (И если операция обновления Op не наследуется таким образом типом T', она не должна наследоваться и никаким подтипом типа T'.) Таким образом, операции обновления должны быть только условно полиморфными – Принцип Полиморфизма Операций (Обновления). Если Op является операцией обновления, P - параметр Op, который является предметом обновления, и T' является таким подтипом объявленного типа T для P, что для T' наследуется Op, то по определению должно быть можно вызывать Op с аргументом-переменной, соответствующим параметру P, когда этот аргумент принадлежит объявленному типу T' – Принцип Возможности Замены (Переменных). IM-предписание 20Объединенный тип (union type) - это такой тип T, что не существует значения, которое принадлежит типу T и не принадлежит какому-либо собственному подтипу T (то есть не существует такого значения v, что MST(v) есть T). Фиктивный тип (dummy type) - это объединенный тип, который не имеет никакого объявленного возможного представления (и, следовательно, никакого селектора); должно разрешаться, чтобы данный объединенный тип был фиктивным типом, если и только если этот объединенный тип не имеет никакого регулярного непосредственного супертипа (где регулярный тип - это тип, который не является фиктивным типом). Более того,
IM-предписание 21Пусть типы T и T' оба являются типами кортежа или оба являются типами отношения с заголовками { <A1,T1>, <A2,T2>, …, <An,Tn> } { <A1,T1'>, <A2,T2'>, …, <An,Tn'> } соответственно. Тогда тип T' является подтипом типа T (или, эквивалентно, тип T является супертипом типа T'), если и только если для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti (или, эквивалентно, тип Ti является супертипом типа Ti'). IM-предписание 22Пусть H - заголовок кортежа или заголовок отношения, определенный следующим образом: { <A1,T1>, <A2,T2>, …, <An,Tn> } Тогда: a. кортеж t соответствует заголовку H, если и только если t имеет вид { <A1,T1',v1>, <A2,T2',v2>, …, <An,Tn,vn> } где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti и vi - значение типа Ti'. c. отношение r соответствует заголовку H, если и только если r состоит из заголовка и тела, где: · Заголовок r имеет вид { <A1,T1'>, <A2,T2'>, …, <An,Tn'> } где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti; · Тело r - это множество кортежей, которые все соответствуют заголовку r. IM-предписание 23Пусть все три типа T, T_alpha, и T_omega - это типы кортежей или типы отношений с заголовками { <A1,T1>, <A2,T2>, …, <An,Tn> } { <A1,T1_alpha>, <A2,T2_alpha>, …, <An,Tn_alpha> } { <A1,T1_omega>, <A2,T2_omega>, …, <An,Tn_omega> } соответственно. Тогда типы T_alpha и T_omega являются максимальным типом по отношению к типу T и минимальным типом по отношению к типу T соответственно, если и только если для всех i (i = 1, 2, …, n) тип Ti_alpha является максимальным типом по отношению к типу Ti и Ti_omega является минимальным типом по отношению к типу Ti. IM-предписание 24Пусть H - заголовок кортежа или заголовок отношения, определенный следующим образом: { <A1,T1>, <A2,T2>, …, <An,Tn> } Тогда:
IM-предписание 25Пусть переменная (кортежа или отношения) V имеет объявленный тип T, и пусть заголовок T имеет атрибуты A1,A2, …, An. Тогда можно моделировать V как множество именованных упорядоченных триплетов вида <DTi,MSTi,vi>, где:
Обозначения DT(Ai), MST(Ai), v(Ai) используются для ссылок на компоненты DTi, MSTi, vi соответственно атрибута Ai этой модели переменной кортежа или отношения V. Мы также используем обозначения DT(V), MST(V), для ссылки на объявленный тип целиком, текущий наиболее конкретный тип целиком и текущее значение целиком соответственно переменной кортежа или отношения V. Отметим, что фактически MSTi(Ai) подразумевается v(Ai), и MST(V) подразумевается v(V). Пусть теперь X - выражение кортежей или отношений. Только что введенные обозначения Dti(V), MSTi(V),vi(V) можно очевидным образом расширить для ссылки на объявленный тип Dti(X), текущий наиболее конкретный тип MSTi(X)и текущее значение vi(X) соответственно компонентов Dti, MSTi, vi атрибута Ai выражения кортежей или отношений X. – где “объявленный тип” - это то, что объяснялось в RM-предписаниях 12 и 13; и этот тип известен во время компиляции, а “текущий наиболее конкретный тип” и “текущее значение” относятся к результату вычисления X и в общем случае неизвестны до времени выполнения. [Назад] [Оглавление] [Вперед] |
|
CITForum © 1997–2025