Программирование >>  Хронологические базы данных 

1 ... 233 234 235 [ 236 ] 237 238 239 ... 348


19.4. Переменные и операция присвоения

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

VAR Е ELLIPSE ; VAR С CIRCLE ;

Сначала проинициализируем переменную С значением некоторой окружности; скажем для определенности, окружности с радиусом 3 и центром в начале координат.

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

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

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

Е := С ;

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

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

Замечание. Ниже, в подразделе Оператор TREAT DOWN , обсуждается процедура получения этого радиуса.

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



Чтобы продолжить рассмотрение примера, предположим, что у нас есть и другая переменная А с объявленным типом AREA.

VAR А AREA ;

Рассмотрим приведенное ниже присвоение. А := AREA ( Е ) ;

В данном случае произойдет следующее.

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

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

Конечно, тот факт, что в данном случае при выполнении оператора AREA вызывается версия, применяемая для окружностей, а не для эллипсов, должен быть скрыт от пользователя (для пользователя, повторим, существует единственный оператор AREA).

Скалярные переменные

Мы уже видели, что текущее значение v скалярной переменной V с объявленным типом Т может относиться к любому подтипу типа Т, равно как и к самому данному типу. Поэтому можно представить модель V в виде упорядоченной тройки вида <DT,MST,v>. Указанные параметры имеют следующий смысл.

DT - объявленный тип переменной V.

MST - текущий конкретный тип переменной V.

V - значение конкретного типа MST, а именно - текущее значение переменной V.

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

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

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



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

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

V := X ;

Здесь V- скалярная переменная, а X- скалярное выражение. Тип 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 ( Е ELLIPSE ) RETURNS ( ELLIPSE ) ;

RETURNS ( E ) ; END OPERATOR ;

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

Оператор TREAT DOWN

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

VAR Е ELLIPSE ; VAR С CIRCLE ;

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



1 ... 233 234 235 [ 236 ] 237 238 239 ... 348

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика