Введение в системы БД (542480), страница 194
Текст из файла (страница 194)
Сигнатуры Термин "снгнатура" означает сочетание имени некоторого оператора и типов операндов данного оператора. (Однако отметим, что у разных авторов и в разных языках программирования в этот термин вкладывается несколько отличный смысл. Например, иногда считается, что к сигнатуре относится тип результата, а иногда — имена операндов и результата.) Поэтому необходимо уточнить различия между некоторыми указанными ниже понятиями. ). Различие между аргументами и параметрами.
2. Различие между объявляемыми типами и реальными (конкретными) типами. 3. Различие между операторами с точки зрения пользователей и операторами с точки зрения системы (имеются в виду явные специализации или скрытые версии этих операторов, как уже объяснялось выше). Фактически мы различаем (хотя в литературе часто этого не делают!) по крайней мере три вида сигнатур, связанных с данным оператором Ор. ° Одна сигнатура определения, которая состоит из имени оператора Ор вместе с объявляемыми типами его параметров в том порядке, в котором параметры указаны в предоставленном пользователю определении данного оператора.
гв В действительности очень мало слиясла в определении новой явной версии именно для данного конкретного случая. (Почему?) 749 Глава 19. Наследование типов Эта сигнатура соответствует оператору Ор с точки зрения пользователя. Например, сигнатурой определения оператора МОЧЕ будет просто сигнатура МОЧЕ(ЕЬЬ1РЗЕ, КЕСТАМОЬЕ)1~. ° Набор сигнатур версий, по одной для каждой явной специализации или версии реализации оператора Ор, в каждой из которых содержатся имя оператора Ор вместе с объявленными типами его параметров в том порядке, в котором эти параметры определены для данной версии.
Такие сигнатуры соответствуют различным частям кода скрытой реализации оператора Ор. Например, сигнатурой версии СК МОЧЕ оператора МОЧЕ будет сигнатура МОЧЕ(С1КСЬЕ, КЕСТАМОЬЕ), ° Набор сигнатур вызова, по одной для каждого возможного сочетания конкретных типов аргументов, в каждой из которых содержатся имя оператора Ор вместе с соответствующим сочетанием конкретных типов аргументов, взятых по порядку. Эти сигнатуры соответствуют различным возможным вариантам вызова оператора Ор (в соотношении "один ко многим", поскольку одна сигнатура может соответствовать многим различным вызовам).
Пусть, например, переменные Е и К имеют соответственно конкретные типы С1КСЬЕ и БООАКЕ. Тогда для вызова опе- ратора МОЧЕ(Е,К) будет применяться сигнатура МОЧЕ(С1КСЬЕ, БООАКЕ). Таким образом, различные сигнатуры вызова используют один и тот же оператор, соответствующий, по крайней мере потенциально, различным версиям реализации данного оператора (т.е. различным скрытым специализациям). Поэтому если несколько версий "одного и того же оператора" выполняются фактически скрыто, значит, выбор каждой версии, вызываемой в любом конкретном случае, будет зависеть от того, какая из версий сигнатуры "лучше подходит" в качестве допустимой сигнатуры вызова.
Процесс выбора наиболее подхолящей версии, т.е. решение о том, какую версию необходимо вызывать, — это, конечно, процесс связывания во время выполнения, как уже отмечалось в разделе 19.3. Кстати, отметим, что сигнатуры определения — это понятие собственно модели; сигнатуры версий — это понятие, относящееся лишь к реализации; сигнатуры вызова — это, хотя в некотором смысле и понятие модели, на самом деле, как и понятие заменимости, непосредственное логическое следствие, в первую очередь, основной идеи наследования типов. В действительности тот факт, что возможно существование различных сигнатур вызова, является просто частью концепции заменимости. ~ ~ В (3.3/ утверждается, чта необходима иметь ваэчажнасть осуществлять разделение между сигнатурай определения для данного оператора и апредвлвниани всех рватааций (версий) этого апв- 1 ратара.
Оскавнав назначение такого разделения — паддвржка фиктивных тлпаа (называемых таклгв "абстрактными" и "зкзечпллранеабразующичи" типачи, или иногда — просто "интерфвйсачи"), т.в, типов, которые саввич нв имеют канкрвл~нага типа какого-либо значения Эти типы позволяют апрвдвллть операторы, кал1арыв причвншны к нвгказькич различным абычныч типач, являющимся собственными падтипами фиктивного типа. Любой из таких операторов затем может быть явно спвциализирааан, т.в, малгвт быть явно определена соответствующая версия оператора для каждага из этих лбы нных падтипав. В кантекстг нашею причвра тип РЕАЛЕ Г1ЯЖБ в указаннач выше смысла мажет быть апредгавн как фиктивный тип, пасла чего сигнатура определения оператора АКЕА малгвт быть сфармулиравана на уровне типа РЬАМЕ Е160КЯ а явные версии реализации апрвдглены длл конкретных лшпав ЕЬЬ1РВЕ РОЬЕВОИи т.д.
Часть )'. Дополнительные аспекть~ Операторы чтения и обновления До сих пор мы негласно подразумевали, что оператор МОЧЕ предназначен лишь для чтения. Однако давайте предположим, что он был определен как оператор обновления. ОРЕКАТОК МОЧЕ ( Е ЕВРЕЕ, К КЕСТАНЙЬЕ ) ОРОАТЕЯ ( Е ) ЧЕКЯ1ОН ЕК МОЧЕ ВЕС?Н ТНЕ СТК ( Е ) ги К СТК ( К ) ЕНО ЕНО ОРЕКАТОК (Напомним, что операторы чтения и обновления иногда называют соответственно наблюдатеяями и.чутаторачзи. См. главу 5, в которой описаны различия между ними.) Заметим, что в результате вызова этой версии оператора МОЧЕ будет изменен его первый аргумент (проще говоря, будет "изменен центр" заданного аргумента) и что обновление выполняется независимо от того, к чему относится первый арзумент: к конкретному типу ЕЬЫРЯЕ либо к конкретному типу С?АСЬЕ.
Иначе говоря, здесь явная специализация для окружностей не требуется'з. Следовательно, преимущество операторов обновления в общем случае заключается в том, что они могут освободить нас от необходимости явно записывать определенные операторы специализации. В частности, обратите внимание на последствия в отношении сопровождения программ. Например, что случится, если впоследствии потребуется ввести тип О С?АСЬЕ, являющийся подтипом типа С?АСЬЕ? Изменение семантики оператора Как мы убедились, при прохождении вниз по иерархии типов всегда можно переопределить реализацию оператора, что имеет одно важное следствие.
Появляется вероятность изменения сачантики данного оператора. Например, может случиться так, что реализация оператора АКЕА для типа С?КСЬЕ реально возвращает, скажем, длину данной окружности вместо плошади. (Тщательное проектирование типов может помочь в некоторой степени смягчить эту проблему. Например, если оператор АКЕА определен как возвращающий результат типа АКВА, то очевидно, что никакая реализация не сможет возвращать результат типа ЬЕНОТН. Однако она может возвращать неверное значение площади!) Более того, хотя это покажется неожиданным, можно даже утверждать (и на самом деле так утверждают), что подобное изменение семантики может быть желательным.
Пусть, например, тип ТОВО Н?ОВНАМИ (Платная дорога) — собственный подтип типа Н?ОННАТ (Дорога), и пусть оператор ТКАЧЕВ Т?МЕ (Время проезда) вычисляет время, затрачиваемое на движение между двумя заданными пунктами на указанной дороге. Для платной дороги оно будет вычисляться по формуле (б/в ) т (пьС), где б — расстояние, в — скорость, и — количество касс для оплаты и Š— время, затрачиваемое на оплату проезда возле каждой кассы.
Для бесплатной дороги время вычисляется, как частное б/а. Приведем еще и обратный пример, т.е. пример, когда изменение семантики, безусловно, нежелательно. Снова рассмотрим эллипсы и окружности. По-видимому, нам бы хотелось, чтобы оператор АКЕА был определен таким образом, чтобы вычисление площа- ~~ На сачам деле явная специализация моягвт быть вовсе нв нуагна, если она поддврягивается ограничениями.
Глава 19. Наследование типов 751 ди данной окружности приводило к одному и тому же результату независимо от того, рассматривается эта окружность именно как окружность или же как эллипс. Другими словами, предположим, что перечисленные ниже события происходят в указанной последовательности. ! . Определяются тип ЕЬЫРЯЕ и соответствующая версия оператора АВЕА.
Предположим для простоты, что код оператора АВЕА не предусматривает использование реальнага представления для эллипсов. 2. Определяется тип С1ВСЬЕ как подтип типа ЕЬЫРБЕ, но пока не определяется отдельная версия реализации оператора АВЕА для окружностей. 3. Вызывается оператор АВЕА для некоторой конкретной окружности с, чтобы получить результат, помещаемый, например, в переменную агеа1. Этот вызов использует, естественно, версию оператора АВЕА для типа ЕЬЫРЯЕ. 4. Определяется собственная версия реализации оператора ЛВЕА для окружностей. 5.
Вновь вызывается оператор АВЕА для той же окружности с, чтобы получить результат, помещаемый, например, в переменную агеа2 (и на этот раз уже используется версия оператора АВЕА для типа С1ВСЬЕ). Нам бы хотелось, конечно, настаивать на том, что условие агеа1=агеа2 должно выполняться. Но это возможное требование ничем не обеспечено, поскольку, как уже отмечалось, всегда существует вероятность того, что версия оператора АВВА, реализованная для окружностей, может возвращать, например, длину окружности вместо плошади или просто неверное значение плошади круга, Теперь возвратимся к примеру с оператором ТВАЧЕЬ ТХМЕ. На самом деле мы считаем этот пример, как и другие подобные ему, крайне неубедительным, т.е.
никак не убеждающим нас в том, что в указанных ситуациях может быть желательным изменение семантики оператора. Рассмотрим возможные последствия. И Если тип ТОЬЬ Н16НИАХ является настоящим подтипом типа Н16НИАХ, это по определению означает, что каждая отдельная платная дорога является фактически дорогой. ° Следовательно, некоторые дороги (т.е. некоторые значения типа Н16НИАХ) являются действительно платными дорогами и имеют кассы для оплаты проезда.
Тогда тип Н16НИАХ вЂ” это не "дороги без касс для оплаты проезда", а "дороги с п кассами для оплаты проезда" (где л может быть равно нулю). м Поэтому оператор ТВАЧЕЬ Т1МЕ для типа Н16НИАХ не "вычисляет время проезда по дорогам, на которых нет касс", а "вычисляет время проезда Ив по некоторым дорогам, игнорируя кассы для оплаты проезда". В Оператор ТВАЧЕЬ Т1МЕ для типа ТОЬЬ Н16НИАХ, напротив, "вычисляет время проезда (г)/а) + (п*Г) по некоторым дорогам, не игнорируя кассы для оплаты проезда".