Как происходит отслеживание свободного экстента? |
Создание объектов и выполняемых систем
6.3. VOID-ссылки
При рассмотрении выполнения build_a_line и значения fancy_line особое внимание следует обратить на ссылки и их связи с объектами.
Начальное состояние ссылки
Предположим, что у нас есть экземпляр класса LINE_BUILDING. Возможно, вы думаете, что поскольку класс объявил запрос fancy_line типа LINE, отсюда всегда следует, что этот экземпляр содержит ссылку на экземпляр LINE, как показано на рисунке:
Это не так. У нас есть объект, показанный слева на рисунке, — экземпляр LINE_BUILDING, с одним полем, соответствующим запросу fancy_line. Давайте предположим, что это объект уже создан в результате вызова "оператора создания", который мы вскоре научимся писать. Этот оператор даст нам только один объект: LINE_BUILDING. Если нам нужен другой объект, то он должен быть явно создан в программе, потому состояние программы сразу после создания экземпляра LINE_BUILDING выглядит так:
Поле fancy_line содержит ссылку. Но поскольку все же нет оператора, создающего другие объекты, ссылка имеет значение void, означающее, что она не присоединена ни к какому объекту. Рисунок отражает принятое соглашение для изображения void-ссылок, напоминая "заземление" в электрических цепях.
Ссылка может находиться в одном из двух возможных состояний.
Определение: состояния ссылкa
- присоединенным к некоторому объекту;
- void.
Предопределенный компонент Void обозначает ссылку. Так что в любой момент выполнения, если x обозначает ссылку, условие
x = Void
имеет значение True, если и только если значение x является void-ссылкой; и
x /= Void
если и только если сущность x присоединена к объекту.
Трудности с void-ссылками
Базисный механизм вычисления был представлен как вызов метода в форме x.f или с аргументами x.f (...). Метод применяется к объекту, к которому x присоединен. Но теперь, при наличии ссылок, возникает возможность, что в некоторый момент выполнения, если верно x = Void, ссылка, которую обозначает x, не присоединена ни к какому объекту. Вызов метода в этом случае будет ошибочным.
Чтобы увидеть эффект от такого "жучка", попытаемся выполнить систему в следующей форме:
class LINE_BUILDING inherit TOURISM feature build_a_line — Построить воображаемую линию и подсветить ее на карте. do Paris .display — Paris .put_line (fancy_line) — Следующая строка должна быть заменена кодом! — "Создать fancy_line и подсветить ее на карте" fancy_line .highlight end fancy_line: LINE end
Как показано, следует временно закомментировать строку Paris.put_line (fancy_line). Эта строка сама по себе содержит ошибку, но нас сейчас интересует другая ошибка.
После начального вызова (Paris.display) выполнение будет прервано, и появится сообщение, указывающее, что встретилось исключение.
То, что случилось, является void-вызовом, или попыткой вызова метода void-целью, — вызовом метода несуществующим объектом. Такая попытка никогда не может быть успешной.
Почувствуй Семантику: Принцип присоединенной цели
При void-вызове возникает исключение: событие, вызывающее прерывание нормального процесса выполнения программы. В данном случае исключение привело к отказу выполнения всей программы. Сообщение EiffelStudio указывает имя происшедшего исключения: "Feature call on void reference" (вызов метода void-ссылкой).
Изучая исключения, мы увидим, что можно избежать отказа, подготовив код обработки исключения, который будет пытаться восстановить ситуацию. Но это приемы "последней надежды". Предотвратить — лучше, чем лечить. Общее правило: всякий раз, когда в программе встречается вызов x.f (...), при котором возможно, что x может быть void, защитите вызов, чтобы он мог выполняться только тогда, когда x присоединен. Примером является библиотечный код, где можно увидеть много проверок вида if x /= Void then ... и предусловий в форме x /= Void, когда x — это аргумент вызова. Вы должны проследить, чтобы цели всех вызовов были присоединенными при каждом выполнении.
Ситуация улучшается. Приложение к этой лекции описывает современную эволюцию, при которой полностью исключается риск void-вызовов.
Если раскомментировать строку Paris.put_line (fancy_line), перекомпилировать и выполнить программу, то произойдет отказ в работе, но по другой причине — нарушено предусловие метода put_line, которое устанавливает, что аргумент не должен быть void (причина того, что эту строку следовало вначале закомментировать, состояла в том, что хотелось вначале познакомиться с ситуацией void-вызова).