Обоснованы ли ограничения?
Обоснованы ли ограничения?
Приведенные выше правила типизации могут иногда показаться слишком строгими. Например, второй оператор в обоих случаях статически отвергается:
1
p:= r; r := p
2
p := r; x := p.diagonal
В (1) запрещается присваивать многоугольник сущности-прямоугольнику, хотя во время выполнения так получилось, что этот многоугольник является прямоугольником (аналогично тому, как можно отказаться принять собаку из-за того, что на клетке написано "животное"). В (2) компонент diagonal оказался не применим к p несмотря на то, что во время выполнения он, фактически, присутствует.
Но более аккуратный анализ показывает, что наши правила вполне обоснованы. Если ссылка присоединяется к объекту, то лучше избежать будущих проблем, убедившись в том, что их типы согласованы. А если хочется применить некоторую операцию прямоугольника, то почему бы сразу не объявить цель прямоугольником?
На практике, случаи вида (1) и (2) маловероятны. Присваивания типа p:= r обычно встречаются внутри некоторых управляющих структур, которые зависят от условий, определяемых во время выполнения, например, от ввода данных пользователем. Более реалистичная полиморфная схема может выглядеть так:
create r.make (...); ...
screen.display_icons -- Вывод значков для разных многоугольников
screen.wait_for_mouse_click -- Ожидание щелчка кнопкой мыши
x := screen.mouse_position -- Определение места нажатия кнопки
chosen_icon := screen.icon_where_is (x) -- Определение значка,
-- на котором находится указатель мыши
if chosen_icon = rectangle_icon then
p := r
elseif ...
p := "Многоугольник другого типа" ...
end
... Использование p, например, p.display, p.rotate, ...
В последней строке p может обозначать любой многоугольник, поэтому можно к нему применять только общие компоненты из класса POLYGON. Понятно, что операции, подходящие для прямоугольников, такие как diagonal, должны применяться только к r (например, в первом предложении if). Если придется использовать p в операторах, следующих за оператором if, то к нему могут применяться лишь операции, применимые ко всем видам многоугольников.
В другом типичном случае p просто является формальным параметром процедуры:
some_routine (p: POLYGON) is ...
и можно выполнять вызов some_routine (r), корректный в соответствии с правилом согласования типов. Но при написании процедуры об этом вызове еще ничего не известно. На самом деле, вызов some_routine (t) для t типа TRIANGLE или любого другого потомка класса POLYGON будет также корректен, таким образом, можно считать, что p представляет некоторый вид многоугольников - любой из их видов. Тогда вполне разумно, что к p применимы только компоненты класса POLYGON.
Таким образом, в случае, когда невозможно предсказать точный тип присоединяемого объекта, полиморфные сущности (такие как p) весьма полезны.