Главная » SQL, Базы данных » АНАЛИЗ ВЗАИМОДЕЙСТВИЯ МЕЖДУ ТИПАМИ И ПОДТИПАМИ НА ПРИМЕРЕ ОКРУЖНОСТЕЙ И ЭЛЛИПСОВ

0

Могут ли экземпляры подтипов рассматриваться как экземпляры типов,  например, действительно ли окружности являются эллипсами? До сих пор в данной главе (на вполне резонных основаниях!) предполагалось, что ответ на этот  вопрос является положительным, но теперь необходимо признать тот факт, что по этому вопросу, который внешне кажется однозначным, в литературе можно найти совершенно противоположные мнения [20.6]. Рассмотрим обычно используемые в этой главе переменные Е и с, которые имеют, соответственно, объявленные типы ELLIPSE и CIRCLE. Предположим, что эти переменные были инициализированы следующим образом.

Е := ELLIPSE ( LENGTH ( 5.0 ), LENGTH ( 3.0 ), POINT ( 0.0, 0.0 ) )

; С := CIRCLE ( LENGTH ( 5.0 ), POINT ( 0.0, 0.0

) ) ;

Отметим, в частности, что теперь оба оператора, ТНЕ_А (С) И ТНЕ_В (С) , возвращают значение пять.

Затем рассмотрим одну операцию, которую можно, безусловно, применить к  переменной Е — "обновление значения полуоси а", например, как показано ниже.

ТН Е_ А    (     Е    )                                        :=     L E NGT H    (    6 . 0     )                                        ;

Но если теперь будет предпринята попытка выполнить аналогичную операцию с переменной с (как показано ниже), то будет получена ошибка!

ТНЕ_А                                        (    С    )                                         :=    LENGTH                                        (     6 . 0                                        )                                         ;

Но в чем именно заключается эта ошибка? Дело в том, что если бы было выполнено это обновление, переменная с в конечном итоге содержала бы "окружность", нарушающую

Глава 20. Наследование типов     801

ограничение, налагаемое на окружности в той части, которая касается условия а = b; a именно: компонент а теперь имел бы значение шесть, тогда как компонент b, безусловно, был бы по-прежнему равен пяти (поскольку в него не были  внесены изменения). Иными словами, переменная с после этого содержала бы "некруглую окружность", нарушая тем самым ограничение типа, наложенное на тип CIRCLE.

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

полуоси а или b окружности (т.е. присваивание ей нового значения) является синтаксически недопустимым. Иными словами, операция присваивания  значений  псевдопеременной ТНЕ_А или ТНЕ_В не применима к типу CIRCLE и попытка подобного обновления должна оканчиваться неудачей из-за ошибки при проверке типов на этапе компиляции.

Примечание. В действительности очевидно, что подобные присваивания и должны быть синтаксически недопустимыми. Напомним, что операция присваивания псевдопеременной ТНЕ_ фактически представляет собой просто сокращение. Поэтому, например, попытка  присваивания  псевдопеременной  ТНЕ_А(С),  если  бы  была  допустимой,  то представляла бы собой сокращенное обозначение примерно следующего оператора.

С   :=   CIRCLE    (    . . .     )    ;

При этом вызов селектора CIRCLE в правой части должен был бы содержать фактический параметр ТНЕ_А со значением LENGTH ( 6 . 0 ) . Но вызов селектора CIRCLE не включает фактический параметр ТНЕ_А! В нем предусмотрен только  фактический параметр THE_R и фактический параметр THE_CTR. Поэтому первоначальное присваивание, безусловно, является недопустимым.

Дополнительные сведения об изменении семантики

Прежде всего, следует немедленно отвергнуть предложение, которое могло быть сделано в попытке спасти от краха идею, что в конечном итоге присваивание псевдопеременной ТНЕ_А или ТНЕ_в должно быть допустимым для окружностей. Такое предложение состоит в том, что операцию присваивания (например)  псевдопеременной ТНЕ_А необходимо переопределить (иными словами, реализовать новую версию этого оператора) для окружностей таким образом, чтобы в качестве побочного эффекта происходило также  присваивание  псевдопеременной  ТНЕ_В,  т.е.  чтобы  окружность  по-прежнему удовлетворяла бы ограничению а = b после обновления. Автор отвергает это предложение по меньшей мере по трем указанным ниже причинам.

■     Во-первых, семантика присваивания псевдопеременным ТНЕ_А и ТНЕ_В является предписанной (вполне сознательно!) в разработанной автором модели и ее не сле дует изменять в предложенной форме.

■     Во-вторых, даже если бы эта семантика не была предписана моделью, в этой книге уже было указано, что в целом не рекомендуется изменять произвольным образом семантику любого оператора, а тем более не рекомендуется изменять семантику лю бого оператора так, чтобы в результате возникали побочные эффекты. Обоснован ный общий принцип состоит в том, что следует неуклонно стремиться к тому, чтобы операторы создавали один и только один требуемый эффект, не больше и не меньше.

■  В-третьих, наиболее важным возражением является то, что возможность  изменения семантики в предложенной форме иногда даже полностью  отсутствует. Например, предположим, что тип ELLIPSE имеет еще один  непосредственный подтип, NONCIRCLE; допустим, что к фигурам,  отличным от окружностей, принадлежащим к этому подтипу, относится  ограничение а > b, и рассмотрим операцию присваивания псевдопеременной ТНЕ_А одной из таких фигур, которая в случае ее успешного выполнения установила бы значение а, равное b. Каким было бы приемлемое переопределение семантики для такого присваивания? Вернее, какой побочный эффект был бы приемлемым?

Поиск применимой модели наследования

Итак, в предыдущих подразделах мы остановились на рассмотрении такой ситуации, что операция присваивания псевдопеременной ТНЕ_А или ТНЕ_В является операцией, которая может применяться к эллипсам в целом, но не к окружностям в частности. Но необходимо также учитывать приведенные ниже соображения.

а)  Предполагается, что тип CIRCLE — это подтип типа ELLIPSE.

б)  Из того, что тип CIRCLE — подтип типа ELLIPSE, следует, что операции, приме нимые к эллипсам в целом, являются применимыми и к окружностям в частности (иными словами, операции с эллипсами наследуются окружностями).

в)  А теперь мы в конечном итоге утверждаем, что операция присваивания псевдопе ременной ТНЕ_А или ТНЕ_В не унаследована.

Разве здесь мы не сталкиваемся с противоречием? Что же в конце концов происходит? Прежде чем попытаться найти ответы на эти вопросы, необходимо подчеркнуть серьезность рассматриваемой проблемы. Приведенный выше довод действительно выглядит как парадокс, поскольку если некоторые операторы не наследуются типом CIRCLE от типа ELLIPSE, то на основании чего именно мы можем утверждать, что окружность является эллипсом? А какой смысл имеет понятие наследование, если некоторые операторы в конечном итоге вообще не  наследуются? Существует ли вообще применимая модель

наследования? Не гоняемся ли мы за призраками, пытаясь найти такую модель?

Примечание. Некоторые авторы вполне серьезно предлагали, чтобы операция  присваивания псевдопеременной ТНЕ_А была допустимой как для окружностей, так и для эллипсов (применительно к окружностям она должна была обновлять радиус), а операция присваивания псевдопеременной ТНЕ_В должна была быть применимой только для эллипсов и поэтому фактически тип ELLIPSE должен был  представлять собой подтип типа CIRCLE! ИНЫМИ словами, эти авторы предлагали развернуть иерархию типов в противоположном направлении. Но достаточно задуматься лишь на мгновение, чтобы понять, что указанная идея является  неприменимой, поскольку, в частности, нарушается принцип заменяемости (например, что такое радиус эллипса общего вида?).

Именно такие соображения, какие были описаны выше, привели некоторых авторов к выводу, что в действительности никакой применимой модели наследования не существует (см. аннотацию к [20.2]). Другие авторы предложили модели наследования с такими средствами, которые противоречат здравому смыслу или, безусловно, являются нежелательными. Например, как показано в  разделе 20.10, стандарт SQL допускает наличие "некруглых окружностей" и других подобных абсурдных объектов. (В стандарте SQL

фактически не поддерживаются ограничения типов, а именно это упущение и становится причиной, по которой этот стандарт допускает существование подобных нелепостей. Об этом также сказано в разделе 20.10.)

Решение задачи определения модели наследования

Подводя итог описанной выше ситуации, можно отметить, что мы столкнулись с описанной ниже дилеммой.

■     Если окружности наследуют операторы "присваивания псевдопеременным ТНЕ_А и ТНЕ_в" от эллипсов, то могут создаваться "некруглые окружности".

■     Способ предотвращения появления "некруглых окружностей" состоит в поддерж ке ограничений типа.

■     Но если поддерживаются ограничения типа, то операторы не могут быть унасле дованы.

■     Итак, оказывается, что наследования в конечном итоге вообще не существует!

Как же разрешить эту дилемму?

Для этого может применяться способ (который часто позволяет выйти из сложной ситуации при обсуждении вопросов теории реляционных баз данных), состоящий в том, что следует признать факт существования важного логического различия между значениями и переменными и действовать в соответствии с этим  фактом. Под выражением "каждая окружность является эллипсом"  подразумевается именно то, что каждое значение окружности является  значением эллипса. Таким образом, это выражение, безусловно, не означает, что каждая переменная окружности является переменной эллипса (переменная с объявленным типом CIRCLE — это не переменная с объявленным типом ELLIPSE и не может содержать значение наиболее конкретного типа ELLIPSE). Иными  словами, наследование применяется  к  значениям,  а  не  к переменным.  Например,  в случае эллипсов и окружностей справедливы приведенные ниже утверждения.

■     Как уже было отмечено, каждое значение окружности представляет собой значе ние эллипса.

■     Поэтому все операции, применимые к значениям эллипсов, применимы также и к значениям окружностей.

■     Но ни с одним значением нельзя выполнить одно действие — изменить его! Если бы мы могли изменять значение, то оно больше не было бы значением. (Безусловно, мы можем "изменить текущее значение" переменной, обновляя эту переменную, но еще раз повторяемом не можем изменить значение как таковое.)

Итак, все операции, применяемые к значениям эллипсов, являются именно  операциями только чтения, которые определены для типа ELLIPSE, а операции, обновляющие переменные типа ELLIPSE, безусловно, являются операциями  обновления, определенными для этого типа. Поэтому приведенное выше утверждение, что "наследование применяется к значениям, а не к переменным", может быть сформулировано более точно, как показано ниже.

■     Операции только чтения наследуются значениями и поэтому, в силу самого этого факта, текущими значениями переменных (поскольку очевидно, что операции толь ко чтения могут на законных основаниях применяться к тем значениям, которые оказались текущими значениями переменных).

Эта более точная формулировка позволяет также объяснить, почему понятия  полиморфизма и заменяемости относятся именно к значениям, а не к переменным. Например (просто, чтобы освежить это в памяти), отметим, что согласно определению заменяемости, всегда можно заменить значение типа т, ожидаемое системой, значением типа T’, где T’ — подтип типа т (полужирным шрифтом отмечены ключевые слова этого определения). И действительно, данный принцип при первом знакомстве с ним был представлен именно как  принцип заменяемости значений (здесь также полужирным шрифтом отмечено ключевое слово).

Что в таком случае можно сказать об операциях обновления? По определению, такие операции относятся к переменным, а не к значениям. Но означает ли это, что можно

утверждать, будто операции обновления, применимые  к переменным типа  ELLIPSE,

наследуются переменными типа CIRCLE?

Скорее всего, такое утверждение будет неправильным, вернее, не совсем правильным. Например, операция присваивания псевдопеременной THE_CTR  может применяться к переменным обоих объявленных типов, но (как было  отмечено выше) операция присваивания псевдопеременной ТНЕ_А таковой не является. Итак, наследование операций обновления должно быть условным; в действительности, необходимо явно определять, какие именно операции  обновления наследуются. В качестве примера можно указать приведенные ниже условия наследования.

■     Переменные объявленного типа ELLIPSE имеют операторы обновления MOVE (это — версия,  предназначенная для обновления)  и  операторы  присваивания псевдопеременным ТНЕ_А, ТНЕ_В и THE_CTR.

■     Переменные объявленного типа CIRCLE имеют операторы обновления MOVE (это — версия,  предназначенная для обновления)  и  операторы  присваивания псевдопеременным THE_CTR и THE_R,  но не псевдопеременной ТНЕ_А или ТНЕ_В.

Примечание. Оператор MOVE рассматривался в предыдущем разделе.

Безусловно, если некоторая операция обновления наследуется, то мы имеем дело с той разновидностью полиморфизма и той разновидностью заменяемости, которые относятся к переменным, а не к значениям. Например, версия оператора MOVE, предназначенная для обновления, принимает фактический параметр, который представляет собой переменную объявленного типа ELLIPSE, но этот оператор можно вызвать и с фактическим параметром, который вместо этого представляет собой переменную объявленного типа CIRCLE (но не с фактическим параметром, являющимся переменной объявленного типа O_CIRCLE!). Поэтому мы можем (и должны) с полным правом обсуждать еще один принцип — принцип заменяемости переменных, но следует учитывать, что этот принцип является более ограничительным, чем принцип заменяемости значений, описанный выше.

Источник: Дейт К. Дж., Введение в системы баз данных, 8-е издание.: Пер. с англ. — М.: Издательский дом «Вильямс», 2005. — 1328 с.: ил. — Парал. тит. англ.

По теме:

  • Комментарии