
2.5. Системы с обобщенными операциями
195
дого типа требуется указать процедуру raise, которая «поднимает» объекты этого типа
на один уровень в башне. В таком случае, когда системе требуется обработать объекты
различных типов, она может последовател ьно поднимать объекты более низких типов,
пока все объекты не окажутся на одном и том же уровне башни. (Упражнения 2.83 и
2.84 касаются деталей реализации такой стратегии.)
Еще одно преимущество башни состоит в том, что легко реализуется представление
о том, что всяк ий тип «наследует» операции своего надтипа. Например, если мы не даем
особой процедуры для нахождения действительной части целого числа, мы все равно
можем ожидать, что real-part будет для них определена в силу того, что целые числа
являются подтипом комплексных. В случае башни мы можем устроить так, чтобы это
происходило само собой, модифицировав apply-generic. Если требуемая операция не
определена непосредственно для типа данного объекта, мы поднимаем е го до надтипа
и пробуем еще раз. Так мы ползем вверх по башне, преобразуя по пути свой аргумент,
пока мы либо не найдем уровень, на котором тр е буемую операцию можно произвести,
либо не доберемся до вершины (и в таком случае мы сдаемся).
Еще одно преимущество башни над иерархией более общего типа состоит в том, что
она дает нам простой способ « опустить» объект данных до его простейшего представле-
ния. Например, если мы складываем 2 + 3i с 4 − 3i, было бы приятно в качестве ответа
получить целое 6, а не комплексное 6 + 0 i. В упражнении 2.85 о бсуждается способ,
которым такую понижающую операцию можно реализовать. (Сложность в том, что нам
нужен общий спосо б отличить объекты, которые можно понизить, вроде 6 + 0i, от тех,
которые понизить нельзя, например 6 + 2i.)
Неадекватность иерархий
Если типы данных в нашей системе естественным образом выстраиваются в баш-
ню, это сильно упрощает задачу работы с обобщенными операциями над различными
типами, как мы только что видели. К сожалению, обычно это не так. На рисунке 2.26
показано более сложное устройство набора типов, а именно отношения между различ-
ными типами геометрических фигур. Мы видим, что в общем случае у типа может быть
более одного подтипа. Напри мер, и треугольники, и четырехугольники я вляются разно-
видностями многоугольников. В дополнение к этому, у типа может быть более одного
надтипа. Например, равнобедр енный прямоугольный треу гольник можно рассматривать
и как равнобедренный, и как прямоугольный. Вопрос с множественными надтипами осо-
бенно болезнен, поскольку из-за него теряется еди ный способ «поднять» тип по иерар-
хии. Нахождение «правильного» надтипа, в котором требуется применить операцию к
объекту, может потребовать долгого поиска по всей сети типов внутри процедуры вроде
apply-generic. Поскольку в общем случае у типа несколько подтипов, существует
подобная проблема и в сдвиге значения «вниз» по иерархии. Работа с большим количе-
ством связ анных типов бе з потери модульности при разработке больших систем – задача
очень трудная, и в этой области сейчас ведется много исследований
52
.
52
Данное утверждение, которое присутствует и в первом издании этой книги, сейчас столь же верно, как
и двенадцать лет назад. Разработка удобного, достаточно общего способа выражать отношения между раз-
личными типами сущностей (то, что философы называют «онтологией»), оказывается невероятно сложным
делом. Основная разница между той путаницей, которая была десять лет назад, и той, которая есть сей-
час, состоит в том, что теперь множество неадекватных онтологических теорий оказалось воплощено в мас-
се соответственно неадекватных языков программирования. Например, львиная доля сложности объектно-