может данная сущность быть полиморфной или нет? Наиболее удивительным выглядит правило (3), по которому полиморфным считается каждый формальный параметр (если его тип не расширен, как в случае с целыми и т. д.). Мы даже не утруждаем себя анализом вызовов. Если у подпрограммы есть аргумент, то он находится в полном распоряжении клиента, а значит, и полагаться на указанный в объявлении тип нельзя. Это правило тесно связано с повторным использованием - целью объектной технологии, - где любой класс потенциально может быть включен в состав библиотеки, и будет многократно вызываться различными клиентами.

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

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

Вызовы, как и сущности, могут быть полиморфными:

Определение: полиморфный вызов

Вызов является полиморфным, если его цель полиморфна.

Оба вызова в наших примерах полиморфны: s.share (g) ввиду полиморфизма s, p.add_ vertex (...) ввиду полиморфизма p. Согласно определению, только квалифицированные вызовы могут быть полиморфны. (Придав неквалифицированному вызову f (...) вид квалифицированного Current.f (...), мы не меняем суть дела, поскольку Current, присвоить которому ничего нельзя, не является полиморфным объектом.)

Далее нам потребуется понятие Кэтколла, основанное на понятии CAT. (CAT - это аббревиатура Changing Availability or Type - изменение доступности или типа). Подпрограмма является CAT подпрограммой, если некоторое ее переопределение потомком приводит к изменениям одного из двух видов, которые, как мы видели, являются потенциально опасными: изменяет тип аргумента (ковариантно) или скрывает ранее экспортировавшийся компонент.

Определение: CAT-подпрограммы

Подпрограмма называется CAT-подпрограммой, если некоторое ее переопределение изменяет статус экспорта или тип любого из ее аргументов.

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

Определение: Кэтколл

Вызов называется Кэтколлом, если некоторое переопределение подпрограммы сделало бы его ошибочным из-за изменения статуса экспорта или типа аргумента.

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

Вызовы share и add_vertex, рассмотренные в наших примерах, являются кэт-коллами. Первый осуществляет ковариантное переопределение своего аргумента. Второй экспортируется классом RECTANGLE, но скрыт классом POLYGON. Оба вызова также и полиморфны, а потому они служат прекрасным примером полиморфных кэтколлов. Они являются ошибочными согласно правилу типов Кэтколл.

Оценка

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

Мы видели три решения проблемы ковариантности, два из которых затронули и вопросы ограничения экспорта. Какое же из них правильное?

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

Глобальный анализ кажется непрактичным из-за полной проверки всей системы. Тем не менее, он помог нам лучше понять проблему.

Решение на основе Закрепления чрезвычайно привлекательно. Оно простое, интуитивно понятное, удобное в реализации. Тем сильнее мы должны сожалеть о невозможности поддержки в нем ряда ключевых требований ОО-метода, отраженных в принципе Открыт-Закрыт. Если бы мы и впрямь обладали прекрасной интуицией, то закрепление стало бы великолепным решением, но какой разработчик решится утверждать это, или, тем более, признать, что такой интуицией обладали авторы библиотечных классов, наследуемых в его проекте?

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

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

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

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату