Создание объектов и выполняемых систем
6.9. Приложение: Избавление от void-вызовов
Это дополнительный материал, описывающий современное состояние исследований на момент публикации.
"Напасти", причиняемые void-вызовами, которые обсуждаются в этой лекции, не являются неизбежными. Современная эволюция языков программирования, в особенности Spec С# (от Microsoft Research) и Eiffel, позволяют полагать, что эта проблема уходит в прошлое.
Версия стандарта ISO для языка Eiffel на самом деле является void-безопасной. Это означает, что компилятор может гарантировать, что во время любого выполнения системы не появятся void-вызовы. Поскольку реализация только появилась на момент написания, в этой книге не используется void-безопасная версия. Здесь представлены несколько элементарных понятий об этом безопасном варианте, позволяющие удовлетворить ваше любопытство.
В ISO-стандарте Eiffel тип, объявленный обычным образом, скажем, CITY, называется присоединенным типом, гарантирующим предотвращение void-ссылок. При объявлении с: CITY ссылка, обозначающая с, конструируется так, что в момент выполнения она всегда будет присоединенной. Тип только тогда допускает void-ссылки, если он объявлен как отсоединяемый тип с ключевым словом detachable, как в s: detachable STOP.
Оба примера репрезентативны, представляя образцы использования.
- Типы, представляющие объекты проблемной области, обычно должны быть присоединенными и, следовательно, исключают void: не бывает в жизни void-города.
- Типы, представляющие связные структуры данных, обычно должны поддерживать void-значения. Мы связывали в цепочку экземпляры STOP, создающие линию метро, заканчивая последнюю остановку void-ссылкой.
Гарантирование отсутствия void-вызовов основано на двух дополняющих приемах.
- Если сущность относится к присоединенному типу, она должна иметь ассоциированный механизм инициализации, запрещающий инициализацию по умолчанию значением Void, как было описано ранее в этой лекции. Как следствие, перед первым вызовом x. f (.) сущность x всегда будет присоединена к объекту.
- Если x относится к отсоединяемому типу, любой вызов должен появляться в контексте, где гарантируется, что x отличен от void, например, if x /= Void then x.f (...) end. Существует фиксированное число обнаруживаемых безопасных возможностей, описанных в стандарте языка и известных как сертифицированные образцы присоединения (Certified Attachment Patterns или CAP).
Проектирование этого механизма поддерживает как совместимость, так и безопасность. Компилятор будет в большинстве случаев принимать обычный код — особенно старый код — таким, как он есть. Исключением является добавление detachable, когда тип должен поддерживать void-значения. Если компилятор отвергает такой код, то обычно это означает существование настоящей проблемы: код несет в себе риск void-вызова в момент выполнения. В таких ситуациях удаление причины отказа означает исправление ошибки, что облегчает работу программиста, а не создает ему помехи.
6.10. Ключевые концепции, изучаемые в этой лекции
- Ссылка либо присоединена к объекту, либо имеет значение void.
- Вызов метода сущностью, такой как x.f (...), будет выполняться должным образом, только если x присоединен к объекту.
- Каждая ссылка изначально имеет значение void и остается таковой в отсутствие любых операций, подобных созданию, которые явно присоединяют объект.
- Void-ссылки служат для указания опущенной информации и для завершения связанных структур.
- Оператор создания, для которого указана цель x, создает новый объект и присоединяет x к этому объекту.
- Синтаксически оператор создания имеет вид create x, или — используя процедуру создания p, специфицированную в классе, — create x.p (arguments).
- Перед выполнением тела процедуры создания, если она задана, выполняется инициализация по умолчанию — поля вновь созданного объекта инициализируются стандартными значениями по умолчанию — ноль для чисел, void для ссылок.
- Оператор создания должен обеспечивать выполнение инварианта класса. Если инициализация по умолчанию не удовлетворяет этому требованию, то оператор должен использовать процедуру создания, исправляющую проблему.
- Выполнение системы состоит из создания экземпляра класса, специфицированного как "корневой класс". Для создания этого "корневого объекта" используется процедура создания класса, специфицированная как "корневая процедура".
- В любой момент выполнения существует текущий объект: объект, запустивший последний выполняемый метод.
- Вызов может быть квалифицированным, примененный к явно указанной цели, или неквалифицированный, примененный к текущему объекту.
- Каждое неквалифицированное упоминание метода должно пониматься (принцип "общей относительности" ОО-программирования) как применение к неявному объекту — текущему объекту, типичному представителю класса.
- Вызовы покрывают многие традиционные операции, некоторые из которых не используют нотацию вызова с точкой. В частности, операции в выражениях являются специальными случаями вызовов, записываемыми в инфиксной или префиксной нотации, что достигается введением псевдонимов (alias) для методов.
- Новые "void-безопасные" механизмы создают возможность (благодаря статическим проверкам, выполняемым компилятором) гарантировать отсутствие void-вызовов во время выполнения.
6-У. Упражнения
6-У.1. Словарь
Дайте точные определения всем терминам словаря.
6-У.2. Карта концепций
Добавьте новые термины в карту концепций, спроектированную в предыдущих лекциях.
6-У.3. Инварианты для точек
Рассмотрите класс POINT с запросами x и y, представляющими декартовы координаты, и ro и theta, представляющими полярные координаты. Напишите часть инварианта, включающую эти запросы. Вы можете использовать подходящие математические функции (функции тригонометрии) и полагать, что арифметические действия выполняются точно.
6-У.4. Current и Void
Может ли Current иметь значение Void?
6-У.5. Присоединенный и отсоединяемый
Приложение к этой лекции описывает новый void-безопасный механизм, основанный на определении каждого типа либо как присоединенного, либо как отсоединяемого. Проанализируйте классы этой лекции (и лекций со 2-й по 4-ю) и установите, должны ли они всегда относиться к присоединенному или отсоединяемому типу, или решение определяется контекстом.