Подбор локальных имен


Смена имен и переопределение

 

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

[x]. Переопределение меняет компонент, но сохраняет его имя.

[x]. Переименование меняет имя, но сохраняет компонент.

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

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

Иногда то и другое можно совмещать:

 

class SANTA_BARBARA inherit

LONDON

rename

foo as fog

redefine

fog

end

...

 

 

Если, как и раньше, l: LONDON ; s: SANTA_BARBARA , и выполнено присваивание l := s , то оба вызова l.foo , s.fog включают переопределенную версию компонента fog , объявление которого должно появиться в предложении feature класса.

Заметьте: redefine содержит уже новое имя компонента. Это нормально, поскольку под этим именем компонент известен классу. Именно поэтому rename должно находиться выше всех остальных предложений наследования (таких, как redefine и пока неизвестные читателю export , undefine , select ). После выполнения rename компонент теряет свой прежний идентификатор и становится известным под новым именем классу, его потомкам и его клиентам.

 

 

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

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

Хорошим примером является класс WINDOW , порожденный от класса TREE . Последний описывает иерархическую структуру, единую для всех деревьев, в том числе и для окон, но имена, понятные в исходном контексте, могут не подходить для интерфейса между WINDOW и его клиентами. Смена имен дает возможность привести их в соответствие с местными обычаями:

 

class WINDOW inherit

TREE [WINDOW]

rename

child as subwindow, is_leaf as is_terminal, root as screen,

arity as child_count, ...

end

RECTANGLE

feature

... Характерные компоненты window ...

end

 

 

Аналогично, класс TREE , который сам порожден от CELL , может сменить имя right на right_sibling и т.д. Путем смены имен класс может создать удобный набор наименований своих "служб" вне зависимости от истории их создания.