Главная » SQL, Базы данных » ПЕРЕМЕННЫЕ И ОПЕРАТОРЫ ПРИСВАИВАНИЯ

0

Предположим, что имеются две переменные Е и с с объявленными типами, соответственно, ELLIPSE и CIRCLE, как показано ниже.

VAR   E   ELLIPSE   ; VAR   С   CIRCLE   ;

Допустим, что происходит инициализация переменной с для определения некоторой окружности, предположим (просто, чтобы этот пример был более конкретным), окружности с радиусом три и центром в начале координат.

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

В этом примере выражение справа от оператора присваивания представляет собой вызов селектора для типа CIRCLE. Как было указано в главе 5, для каждого объявленного возможного представления предусмотрен конкретный оператор селектора с тем же именем и с формальными параметрами, соответствующими компонентам рассматриваемого возможного представления. Назначение селектора состоит в том, чтобы дать пользователю возможность определять или  "выбирать"  значение рассматриваемого типа, предоставляя значение для каждого компонента рассматриваемого возможного представления.

Примечание. Для упрощения здесь и дальше в этой главе предполагается, что декартово  возможное  представление  для  точек  называется  POINT, а  не  (как  в  главе  5) CARTESIAN. Поэтому вторым фактическим параметром в селекторе CIRCLE в данном примере является вызов этого селектора декартовых координат для точек.

Теперь рассмотрим следующий оператор присваивания.

Е   :=   С   ;

В обычных обстоятельствах (т.е. в отсутствие применения подтипов и наследования) для выполнения соответствующей операции присваивания  требуется, чтобы значение, представленное выражением в правой части, имело тот же тип (а именно, объявленный тип), что и переменная в левой части. Но из принципа заменяемости значений следует, что  в  любом  месте,  где  система  ожидает  значение  типа  ELLIPSE,  всегда  можно подставить значение типа  CIRCLE, поэтому данная операция присваивания является допустимой  (фактически  операция  присваивания  является  полиморфной).  Кроме того, действие этой операции сводится к тому, что значение окружности копируется из переменной С

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

■     Значения сохраняют свой наиболее конкретный тип после их присваивания перемен ным наименее конкретного объявленного типа. При таком присваивании преобразо вание типов не происходит6 (в данном примере окружность не преобразуется так, чтобы она стала "просто эллипсом"). Следует также отметить, что нам и не нужно, чтобы выполнялись какие-либо подобные преобразования, поскольку они приве ли бы к потере наиболее конкретных функциональных свойств рассматриваемого значения. Например, в данном случае применение такого преобразования означало бы, что после присваивания мы теряем возможность определить радиус из значе ния окружности в переменной Е. (См. подраздел "Оператор TREAT DOWN", приве денный ниже в данном разделе, где описано, какие действия необходимо выпол нить для решения указанной задачи определения радиуса.)

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

Продолжая приведенный выше пример, предположим, что теперь предусмотрена еще одна переменная А с объявленным типом AREA, как показано ниже.

VAR  A  AREA   ;

Рассмотрим следующий оператор присваивания.

А   :=   AREA   (   Е   )     :

Ниже описано, что происходит при выполнении данного оператора.

■     Во-первых, система выполняет проверку типов на этапе компиляции выражения AREA(E) . Эта проверка завершается успешно, поскольку Е относится к объявлен ному типу ELLIPSE, а единственный формальный параметр оператора AREA также относится к объявленному типу ELLIPSE, как показано в разделе 20.2.

■     Во-вторых, система на этапе прогона обнаруживает, что текущим наиболее кон кретным типом переменной Е (вернее, хранящегося в ней значения) является CIRCLE, и поэтому вызывает версию оператора AREA, которая относится к окруж ностям; иными словами, система выполняет процесс связывания на этапе прого на, описанный в предыдущем разделе.

Безусловно, тот факт, что вызывается версия оператора AREA, относящаяся к окружностям, а не версия для типа ELLIPSE, не должен заботить пользователя; еще раз отметим, что с точки зрения пользователя существует только один onepaтop AREA.

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

Переменные

Выше было показано, что текущее значение v переменной V объявленного типа т может иметь любой подтип типа т в качестве своего наиболее конкретного типа. Из этого следует, что существует возможность моделировать переменную v как упорядоченную тройку в форме <DT, MST, v>. Здесь используются обозначения, описанные ниже.

■     DT. Объявленный тип (Declared Type — DT) переменной V.

■     MST. Текущий наиболее конкретный тип (Most Specific Type — MST) для перемен ной V (под этим подразумевается наиболее конкретный тип значения, которое яв ляется текущим значением переменной V).

■     v. Значение наиболее конкретного типа MST, а именно текущее значение перемен ной V.

Для обозначения компонентов DT, MST и v рассматриваемой модели  переменной V будут использоваться, соответственно, обозначения DT (V), MST (v) и v (V). Необходимо учитывать следующее: во-первых, MST (V) всегда представляет собой подтип (причем не обязательно строгий подтип) типа DT (V); во-вторых, компоненты MST (V) и v (V) в общем могут изменяться во времени; в-третьих, компонент MST (V) фактически определяется компонентом v (V), поскольку каждое значение относится к одному и только одному наиболее конкретному типу.

Эта модель переменной может применяться для подробного анализа семантики различных операций, включая, в частности, операции присваивания. Но прежде  чем приступить к этому анализу, необходимо пояснить, что понятия объявленного типа и текущего наиболее конкретного типа могут быть очевидным образом дополнены, чтобы они могли применяться не только к простым переменным, но и к произвольным выражениям. Допустим, что х— такое выражение, a v(X) — результат вычисления этого выражения. В таком случае справедливы приведенные ниже утверждения.

■     Выражение х имеет объявленный тип DT (X), а именно объявленный тип операто ра Oр, который вызывается на самом внешнем уровне выражения X. Тип DT(X) становится известным на этапе компиляции.

■     Выражение х имеет также текущий наиболее конкретный тип MST(X), а именно тип, который является наиболее конкретным типом значения v(X). Тип MST(X) (в общем) остается неизвестным до этапа прогона.

Теперь мы можем приступить к подробному описанию действия оператора присваивания. Рассмотрим следующий оператор присваивания.

V   : =   X   ;

Здесь V — переменная, а х —  выражение. Тип DT (X) должен быть подтипом типа DT(V) , так как в противном случае этот оператор присваивания становится недопустимым (проверка происходит на этапе  компиляции). А если оператор присваивания является допустимым, то результат его действия сводится к тому, что тип MST (V) становится равным типу MST (X), а значение v (V) — равным значению v(X).

Кстати, следует отметить, что если текущий наиболее конкретный тип переменной V равен т, то каждый строгий супертип типа т также является "текущим типом" переменной V.

Например, если переменная Е (объявленного типа ELLIPSE) имеет текущее  значение наиболее конкретного типа CIRCLE, то "текущими типами" Е являются сразу все типы — CIRCLE, ELLIPSE и PLANE_FIGURE. Но выражение "текущий тип X" обычно применяется, по меньшей мере, неформально для обозначения именно наиболее конкретного типа MST(x).

Дополнительные сведения о заменяемости Рассмотрим следующее определение оператора.

OPERATOR COPY ( E ELLIPSE )

RETURNS ELLIPSE ; RETURN ( E ) ; END OPERATOR ;

Благодаря использованию заменяемости оператор COPY можно вызвать с указанием в качестве фактического параметра наиболее конкретного типа либо типа ELLIPSE, либо типа CIRCLE, и, безусловно, к какому бы типу ни относился этот фактический параметр, оператор COPY должен возвратить результат с  тем же наиболее конкретным типом. Поэтому из определения заменяемости  вытекает еще одно следствие, что если оператор Ор определен как имеющий  результат объявленного типа т, то фактический результат вызова оператора Ор может (в общем) относиться к любому подтипу типа т. Иными словами, так же как, во-первых, ссылка на переменную объявленного типа т может (в общем)  фактически указывать на значение любого подтипа типа т, так и, вовторых, вызов любого оператора с объявленным типом т может (опять-таки, в общем) фактически возвращать значение любого подтипа типа т.

Оператор TREAT DOWN

Еще раз рассмотрим пример, приведенный в начале данного раздела.

VAR E ELLIPSE ; VAR С CIRCLE ;

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

Е := С ;

Теперь  компонент  модели  переменной  MST(E)  представляет  собой  тип  CIRCLE. Поэтому предположим, что требуется определить радиус рассматриваемого окружности и присвоить его некоторой переменной L. Первая попытка выполнить такое действие может состоять в следующем.

VAR L LENGTH ;

L := THE_R ( E ) ; /* Ошибка несоответствия типов на этапе

компиляции ! ! ! */

Но, как указано в комментарии к этому коду, попытка его применения оканчивается неудачей из-за ошибки при проверке типа на этапе компиляции. А  именно, такое неудачное завершение происходит из-за того, что оператор THE_R ("оператор определения радиуса"), присутствующий в правой части оператора  присваивания, требует использования фактического параметра типа CIRCLE, а объявленным типом переменной Е является ELLIPSE, а не CIRCLE. Следует отметить, что если бы такая проверка типов на этапе компиляции не была выполнена, то мы получили бы вместо ошибки времени компиляции ошибку из-за несоответствия типов на этапе прогона (а это гораздо хуже) в случае

обнаружения того, что значение Е на этапе прогона представляет собой просто эллипс, а не окружность. Тем не менее, в рассматриваемой ситуации нам  известно,  что на этапе прогона данное значение будет представлять собой окружность, но вся сложность состоит в том, что мы это знаем, а компилятор— нет.

Для решения подобных проблем автор предлагает ввести новый оператор и присвоить ему неформальное название TREAT DOWN ("рассматривать как относящийся к подтипу"). В таком случае правильный способ получения радиуса в данном примере становится таким, как показано ниже.

L := THE_R ( TREAT_DOWN_AS_CIRCLE ( E ) ) ;:

Выражение TREAT_DOWN_AS_CIRCLE(E) определяется как относящееся к  объявленному типу CIRCLE, поэтому теперь проверка типов на этапе компиляции оканчивается успешно. Затем на этапе прогона осуществляются описанные ниже действия.

■     Если текущее значение переменной Е действительно относится к типу CIRCLE, то все это выражение успешно возвращает радиус данной окружности. Точнее, вызов оператора TREAT DOWN приводит к получению некоторого результата, скажем, z, который, во-первых, имеет объявленный тип DT ( Z ), равный CIRCLE, поскольку задана спецификация ". . ._AS_CIRCLE" ("… как окружность"); во-вторых, отно сится к текущему наиболее конкретному типу MST(Z), равному MST(E), который в данном примере также представляет собой CIRCLE; в-третьих, имеет текущее значение v( Z) , равное v( E) ; наконец,  в-четвертых,  вычисляется выражение "THE_R(Z)", позволяющее получить требуемое значение радиуса (которое затем может быть присвоено переменной L).

■     Но если текущее значение Е относится только к типу ELLIPSE, а не к типу CIRCLE, то выполнение оператора TREAT DOWN на этапе прогона оканчивается неудачей из-за ошибки, связанной с несоответствием типов.

Общее назначение оператора TREAT DOWN СОСТОИТ В обеспечении того, чтобы ошибки из-за несоответствия типов ко время прогона могли возникать только в контексте вызова самого оператора TREAT DOWN.

Примечание. Предположим, что тип CIRCLE, в свою очередь, имеет строгий подтип, скажем, O_CIRCLE (О-окружность; здесь под "О-окружностью" подразумевается окружность с центром в начале координат), который определен, как показано ниже.

TYPE O_CIRCLE IS CIRCLE

CONSTRAINT THE_CTR ( CIRCLE ) = POINT ( 0.0, 0.0 ) POSSREP { R = THE_R ( CIRCLE ) } ;

В таком случае в некоторый момент времени текущее значение переменной Е может относиться к наиболее конкретному типу O_CIRCLE, а не просто CIRCLE. Если дело обстоит таким образом, то приведенный ниже вызов оператора TREAT  DOWN завершится успешно.

TREAT_DOWN_AS_CIRCLE    (  Е  )

Этот вызов приведет к получению результата, скажем, Z, такого что, во-первых,

его тип DT(Z)  равен CIRCLE, поскольку задана спецификация ". . ._AS_CIRCLE";

во-вторых, тип MST(Z) равен O_CIRCLE, поскольку O_CIRCLE — наиболее конкретный тип переменной Е; и в-третьих, значение v(Z) равно v(E). Иными словами (выражаясь неформально), оператор TREAT DOWN всегда оставляет неизменным наиболее конкретный тип и ни при каких обстоятельствах "не продвигает его вверх по иерархии типов", чтобы он стал менее конкретным, чем перед этим.

Ниже приведено предназначенное для использования в будущем более  формальное определение семантики вызова оператора TREAT_DOWN_AS_T(X) ,  где  х— некоторое выражение. Во-первых, тип MST(X) должен быть подтипом типа Т (проверка этого выполняется на этапе прогона); если предположить, что  это условие удовлетворяется, то данный вызов возвращает результат Z с типом DT(Z) , равным т, типом MST (Z), равным MST(X), и значением v( Z) , равным v(X).

Примечание. В [3.3] определена также обобщенная форма оператора TREAT DOWN, которая позволяет рассматривать один операнд как относящийся к типу другого, а не как относящийся к некоторому явно указанному типу.

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

По теме:

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