Rationale for Ada 2005: Object oriented model
RUSTOPBACKNEXT
ENG |
5. Nested type extension
@ In Ada 95 type extension of tagged types has to be at the same level as the parent type. This can be quite a problem. In particular it means that all controlled types must be declared at library level because the root types Controlled and Limited_Controlled are declared in the library level package Ada.Finalization. The same applies to storage pools and streams because again the root types Root_Storage_Pool and Root_Stream_Type are declared in library packages. @ This has a cumulative effect since if we write a generic unit using any of these types then that package can itself only be instantiated at library level. This enforces a very flat level of programming and hinders abstraction. @ The problems can actually be illustrated without having to use controlled types or generics. As a simple example consider the following which is adapted from a text book [3]. It manipulates lists of colours and we assume that the type Colour is declared somewhere.
|
|
|
|
|
|
Rationale for Ada 2005: Object oriented model
@ENGRUSTOPBACKNEXT5. Вложенное расширение типов
@ В Аде 95 расширения тегового типа должны выполняться на том же самом уровне что и его родительский тип. Это может быть настоящей проблемой. Это означает, что все управляемые (controlled) типы должны быть объявлены на библиотечном уровне, потому что корневые типы Controlled и Limited_Controlled объявлены на библиотечном уровне пакета Ada.Finalization. То же самое относится к пулам памяти и потокам, потому что кореневые типы Root_Storage_Pool и Root_Stream_Type объявлены в библиотечных пакетах.
@ Последствием всего этого является то что, если мы пишем настраиваемый модуль использующий любой из этих типов, то наш пакет должен быть проиллюстрирован на библиотечном уровне. Это претворяет в жизнь очень плоский уровень программирования и препятствует абстракции.
@ Эти проблемы могут быть проиллюстрированы без необходимости использования контролируемых (controlled) типов или настраиваемых средств. Рассмотрим простой пример из учебника [3]. Он управляет списками цветов, и мы предполагаем, что тип Color где-то уже объявлен:
|
@ Идея здесь в том, что процедура Iterate вызывает процедуру Action для каждого объекта списка, и таким образом предоставляет доступ к цвету соответствующего объекта. Пользователь должен объявить расширение Iterator и процедуру Action для каждого объекта.
@ Некоторые читатели могут найти это весьма запутанным. Это проще понять, если посмотреть на частную секцию и тело пакета Lists:
|
@ Отметим использование анонимных ссылочных типов, которые избавляют от необходимости иметь неполное объявление Cell в частной секции.
@ Теперь предположим, что мы желаем изменить цвет каждого зеленого объекта на красный. Мы пишем (на некотором библиотечном уровня пакета)
|
@ Это работает, но не идеально. Тип GTR_It и процедура Action не должны быть объявлены вне процедуры Green_To_Red, так как они - действительно только часть ее внутренних работ. Но мы не можем объявить тип GTR_It в процедуре на Аде 95 потому что, это было бы расширением на внутреннем уровне.
@ Дополнительные средства предопределенной библиотеки Ады 2005 и особенно введение контейнеров, которые естественно реализованы как настраиваемые модули, вызвали повторное рассмотрение причин для ограничения расширения типов ada. Опасность вложенного расширения конечно состоит в том, что значения объектов могут нарушить правила доступности и пережить их описание типа. В конце-концов было решено, что расширение типа может быть разрешено на вложенных уровнях с выполнением только некоторых проверок для гарантии, что правила доступности не были нарушены.
@ Так на Аде 2005 процедура Green_To_Red может быть написана как:
|
@ и все работы теперь происходят в пределах процедуры, как это и должно быть.
@ Кстати, обратите внимание, что мы теперь можем использовать нотацию It.Iterate (L) даже при том, что тип GTR_It не объявлен в пакете. Помните, что, хотя мы не можем добавить новые операции диспетчеризации к типу, если это не объявлено в спецификации пакета, однако мы можем всегда заменять (override) существующие, такие как Action.
@ Этот пример весьма безопасен, и ничто в нём не может пойти не так как надо несмотря на то, что мы выполнили расширение на внутреннем уровне. Это потому что значение It не переживает выполнение процедуры Action.
@ Но предположим, что у нас есть надклассовый объект Global_It:
|
@ Теперь мы находимся в глубокой задумчивости. Мы возвратили значение локального типа Bad_It, назначили начальное значение Global_It и затем послали её процедуре Action. Но процедура Action, которая будет вызвана, является внутренней частью Dodgy, которая не существует больше, так как мы оставили функцию Dodgy. Но этому нельзя позволить случиться.
@ Таким образом, требуются некоторые проверки доступности. Есть проверка по возвращению из функции с наклассовым результатом, что у возвращаемого значения нет тэгового типа на более глубоком уровне чем функции непосредственно. Так в этом примере есть проверка по возвращению из функции Dodgy она проводится и возбуждает исключение Program_Error, и таким образом, всё хорошо.
@ Есть подобные проверки на надклассовые программы распределения и когда используется T'Class'Input или T'Class'Output. Некоторые из них могут быть выполнены во время компиляции, но другие должны быть проверены во время выполнения, и они также возбуждат Program_Error, если они терпят неудачу.
@ Кроме того, чтобы осуществить проверки, связанные с T'Class'Input и T'Class'Output, в пакете Ada.Tags объявлены две дополнительные функции:
|
@ Их использование будет показано в следующем разделе.
2010-10-31 15:31:38
. .