14.2. Обработка исключений 139
error try Расширяет λ с ошибками (14.1)
Новые синтаксические формы
t ::= . . . термы:
try t with t ловля ошибок
Новые правила вычисления t t
try v
1
with t
2
v
1
(E-TryV)
try error with t
2
t
2
(E-TryError)
t
1
t
1
try t
1
with t
2
try t
1
with t
2
(E-Try)
Новые правила типизации Γ t : T
Γ t
1
: T Γ t
2
: T
Γ try t
1
with t
2
: T
(T-Try)
Рис. 14.2. Обработка ошибок
14.2. Обработка исключений
Правила вычисления для error можно рассматривать как «откатывание стека вызовов» с отбра-
сыванием ждущих вызовов функций до тех пор, пока ошибка не распространится до самого верхнего
уровня. В настоящих реализациях языков с исключениями ровно это и происходит: стек вызовов состо-
ит из множества записей активации, по одной на каждый активный вызов функции; когда возникает
исключение, записи активации снимаются со стека вызовов, пока он не опустеет.
В большинстве языков с исключениями также присутствует возможность установить в стеке вы-
зовов обработчики исключений. Когда возникает исключение, записи активации снимаются со стека
вызовов до тех пор, пока на вершине не окажется обработчик исключений, и тогда вычисление про-
должается с этого обработчика. Другими словами, исключение работает как нелокальная передача
управления, целью которой является ближайший установленный обработчик исключений (ближайший
на стеке вызовов).
Наша формулировка обработчиков исключений, приведенная на Рис. 14.2, похожа как на ML, так
и на Java. Выражение try t
1
with t
2
означает «вернуть результат вычисления t
1
, если при этом не
возникнет ошибка; иначе выполнить обработчик t
2
». Правило вычисления E-TryV говорит, что, когда
терм t
1
свелся к значению v
1
, конструкцию try можно отбросить, поскольку мы уже знаем, что она
не понадобится. С другой стороны, E-TryError говорит, что, если при вычислении t
1
получилась
ошибка error, то нам следует заменить конструкцию try термом t
2
и продолжить его вычисление. E-
Try говорит, что, до тех пор, пока t
1
не свелся ни к значению, ни к error, следует просто продолжать
его вычислять, не трогая t
2
.
Правило типизации для try прямо следует из его операционной семантики. Результатом всей кон-
струкции try может быть либо результат главного тела t
1
, либо результат обработчика t
2
; нужно
просто потребовать, чтобы оба они имели один и тот же тип T, который также будет типом всего try.
Свойство типовой безопасности и его доказательство, по существу, остаются неизменными по срав-
нению с предыдущим разделом.
14.3. Исключения, сопровождаемые значениями
Механизмы: введенные нами в §14.1 и §14.2, позволяют функции сообщить своей вызывающей про-
грамме, что «случилось нечто необычное». Как правило, полезно бывает отсылать также некоторую
дополнительную информацию о том, что за необыкновенное событие произошло, поскольку действие,
которое должен предпринять обработчик — либо попытаться исправить ситуацию и вызвать функцию
заново, либо выдать понятное сообщение пользователю, — может зависеть от этой информации.
На Рис. 14.3 показано, как наши базовые конструкции для обработки ошибок могут быть расшире-
ны, чтобы каждое исключение было снабжено значением. Тип этого значения записывается T
exn
. Пока
что мы оставляем открытым вопрос, что это за тип; ниже обсуждается несколько альтернатив.
rev. 104