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

1 ... 237 238 239 [ 240 ] 241 242 243 ... 348


Оператор MOVE выполняет перемещение эллипса Е таким образом, что его центр помещается в центр прямоугольника R. Точнее говоря, он возвращает эллипс, который в точности соответствует эллипсу, указанному его параметром Е, но центр возвращаемого эллипса совпадает с центром прямоугольника, заданного параметром R. Обратите внимание, что фраза VERSION во второй строке определения вводит еще одно имя, ER MOVE, используемое именно для конкретной версии оператора MOVE (подробности приводятся в следующем разделе). Кроме того, обратите внимание, что неявно предполагается существование оператора R CTR, который возвращает координаты центра заданного прямоугольника.

А теперь предположим, что существует механизм явной специализации, т.е. требуется определить другую версию оператора MOVE, выполняющего перемещение окружностей, а не эллипсов.

OPERATOR MOVE ( С CIRCLE, R RECTANGLE ) RETURNS ( CIRCLE ) VERSION CR MOVE ;

RETURN ( CIRCLE ( THE R ( С ), R CTR ( R ) ) ; END OPERATOR ;

Аналогично можно было бы получить явную специализацию для оператора MOVE (скажем, ES MOVE), если бы аргументы имели соответственно конкретные типы ELLIPSE и SQUARE, а аргументы конкретных типов CIRCLE и SQUARE, например, - CS MOVE.

Сигнатуры

Термин сигнатура означает сочетание имени некоторого оператора и типов операндов данного оператора. (Однако отметим, что у разных авторов и в разных языках профаммирования в этот термин вкладывается несколько отличный смысл. Например, иногда считается, что к сигнатуре относится тип результата, а иногда- имена операндов и результата.) Поэтому необходимо уточнить различия между некоторыми указанными ниже понятиями.

1. Различие между аргументами и параметрами.

2. Различие между объявляемыми типами и реальными (конкретными) типами.

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

Фактически мы различаем (хотя в литературе часто этого не делают!) по крайней мере три вида сигнатур, связанных с данным оператором Ор.

Одна сигнатура определения, которая состоит из имени оператора Ор вместе с объявляемыми типами его параметров в том порядке, в котором параметры указаны в предоставленном пользователю определении данного оператора.

В действительности очень мало смысла в определении новой явной версии именно для данного конкретного случая. (Почему?)



Эта сигнатура соответствует оператору Ор с точки зрения пользователя. Например, сигнатурой определения оператора MOVE будет просто сигнатура MOVE (ELLIPSE, RECTANGLE)

Набор сигнатур версий, по одной для каждой явной специализации или версии реализации оператора Ор, в каждой из которых содержатся имя оператора Ор вместе с объявленными типами его параметров в том порядке, в котором эти параметры определены для данной версии. Такие сигнатуры соответствуют различным частям кода скрытой реализации оператора Ор. Например, сигнатурой версии CR MOVE оператора MOVE будет сигнатура MOVE (CIRCLE, RECTANGLE).

Набор сигнатур вызова, по одной для каждого возможного сочетания конкретных типов аргументов, в каждой из которых содержатся имя оператора Ор вместе с соответствующим сочетанием конкретных типов аргументов, взятых по порядку. Эти сигнатуры соответствуют различным возможным вариантам вызова оператора Ор (в соотношении один ко многим , поскольку одна сигнатура может соответствовать многим различным вызовам). Пусть, например, переменные Е и R имеют соответственно конкретные типы CIRCLE и SQUARE. Тогда для вызова оператора MOVE(E,R) будет применяться сигнатура MOVE (CIRCLE, SQUARE).

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

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

В [3.3] утверждается, что необходимо иметь возможность осуществлять разделение между сигнатурой определения для данного оператора и определениями всех реализаций (версий) этого оператора. Основное назначение такого разделения - поддержка фиктивных типов (называемых также абстрактными и экземпляронеобразующими типами, или иногда- просто интерфейсами ), т.е. типов, которые совсем не имеют конкретного типа какого-либо значения. Эти типы позволяют определять операторы, которые применимы к нескольким различным обычным типам, являющимся собственными подтипами фиктивного типа. Любой из таких операторов затем может быть явно специализирован, т.е. может быть явно определена соответствующая версия оператора для каждого из этих обычных подтипов. В контексте нашего примера тип PLANE FIGURE в указанном выше смысле мажет быть определен как фиктивный тип, после чего сигнатура определения оператора AREA может быть сформулирована на уровне типа PLANE FIGURE, а явные версии реализации определены для конкретных типов ELLIPSE, POLYGON и т.д. >



Операторы чтения и обновления

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

OPERATOR MOVE ( Е ELLIPSE, R RECTANGLE ) UPDATES ( E ) VERSION ER MOVE ; BEGIN ;

THE CTR ( E ) := R CTR ( R ) ; END ; END OPERATOR ;

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

Заметим, что в результате вызова этой версии оператора MOVE будет изменен его первый аргумент (проще говоря, будет изменен центр заданного аргумента) и что обновление выполняется независимо от того, к чему относится первый аргумент: к конкретному типу ELLIPSE либо к конкретному типу CIRCLE. Иначе говоря, здесь явная специализация для окружностей не тpeбyeтcя2. Следовательно, преимущество операторов обновления в общем случае заключается в том, что они могут освободить нас от необходимости явно записывать определенные операторы специализации. В частности, обратите внимание на последствия в отношении сопровождения программ. Например, что случится, если впоследствии потребуется ввести тип 0 CIRCLE, являющийся подтипом типа CIRCLE?

Изменение семантики оператора

Как мы убедились, при прохождении вниз по иерархии типов всегда можно переопределить реализацию оператора, что имеет одно важное следствие. Появляется вероятность изменения семантики данного оператора. Например, может случиться так, что реализация оператора AREA для типа CIRCLE реально возвращает, скажем, длину данной окружности вместо площади. (Тщательное проектирование типов может помочь в некоторой степени смягчить эту проблему. Например, если оператор AREA определен как возвращающий результат типа AREA, то очевидно, что никакая реализация не сможет возвращать результат типа LENGTH. Однако она может возвращать неверное значение площади!)

Более того, хотя это покажется неожиданным, можно даже утверждать (и на самом деле так утверждают), что подобное изменение семантики может быть желательным. Пусть, например, тип T0LL HIGHWAY (Платная дорога)- собственный подтип типа HIGHWAY (Дорога), и пусть оператор TRAVEL TIME (Время проезда) вычисляет время, затрачиваемое на движение между двумя заданными пунктами на указанной дороге. Для платной дороги оно будет вычисляться по формуле (d/s) + (n*t), где d - расстояние, S - скорость, п - количество касс для оплаты и t - время, затрачиваемое на оплату проезда возле каждой кассы. Для бесплатной дороги время вычисляется, как частное d/s.

Приведем еще и обратный пример, т.е. пример, когда изменение семантики, безусловно, нежелательно. Снова рассмотрим эллипсы и окружности. По-видимому, нам бы хотелось, чтобы оператор AREA был определен таким образом, чтобы вычисление площа-

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



1 ... 237 238 239 [ 240 ] 241 242 243 ... 348

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