В целом, стратегии обработки ошибок можно разделить на три категории:
- Ничего не делать (
ON ERROR RESUME NEXT
, как упоминал Райан)
- Указывает на ошибку / сбой в коде возврата. В некоторых случаях это может быть дополнительный выходной параметр, например указатель на индикатор ошибки, который устанавливается в случае ошибки.
- Вызвать альтернативный поток управления. Это может быть экстремально (вызывая
abort()
для остановки программы), или принимать форму обработки исключений или что-то подобное.
Существует ряд реализаций и стилей альтернативных потоков управления. Одним из них являются сигналы POSIX, которые часто приводят к завершению программы по умолчанию. Visual Basic также имеет альтернативное средство управления потоком в ON ERROR GOTO
.
Perl объединяет альтернативные потоки управления и коды возврата, используя die
, что приводит к завершению программы в таких субинтерпретаторах, что при выполнении die
в блоке eval
'код вызова устанавливается в вызывающем код.
Затем, конечно, существует традиционная обработка исключений, а также такие вариации, как перезапускаемые / возобновляемые исключения Common Lisp. Даже сигнал / abort()
подход и ON ERROR GOTO
могут считаться примитивными системами обработки исключений. Таким образом, рассматривая исключения в целом, большинство систем обработки ошибок альтернативного потока управления можно рассматривать как некоторую форму обработки исключений.
Фактически реализация исключений открывает интересный набор пространств проектирования. Языковая реализация может сделать это несколькими способами:
- Установить флаг / ненормальное возвращаемое значение и вернуть вызывающего. Perl требует от вас явного выполнения -
die
и проверки переменной ошибки $?
- это ручная версия этого метода. При этом язык программирования использует метод обработки ошибок кода возврата для реализации исключений и может предоставлять их с помощью конструкции try-catch; Вала является хорошим примером этого.
- Размотайте стек (как если бы функции возвращались) обработчику исключений и запустите его. Это может быть сделано напрямую, либо с помощью оборудования VM, либо путем проверки стека. Это также можно смоделировать с помощью (2); при использовании для реализации исключений эти два подхода в значительной степени семантически эквивалентны.
- Вызвать код обработки исключений в динамической области кода, выдавшей ошибку. Это то, что Common Lisp делает со своей конструкцией
condition-case
- обработчик ошибок запускается без разматывания стека и затем указывает, должна ли ошибка быть обработана путем повторной попытки или разматывания.
- Использовать двустороннее продолжение прохождения . В обычном стиле прохождения продолжения (CPS), вместо того, чтобы возвращать значение, функция вызывает другую функцию (называемую продолжением), которая предоставляется вызывающей стороной в качестве одного из аргументов с результатом, чтобы «продолжить» вычисление. В CPS с двумя стволами вызывающая сторона предоставляет два продолжения: одно для нормальных результатов и одно для ошибок. Это может использоваться для реализации семантики, эквивалентной (1) и (2), но представляет собой интересную альтернативную стратегию, которая может открыть возможность для создания более интересной семантики.
Итак, в итоге: существует три основных подхода: игнорировать ошибки, коды возврата и различные средства, подобные исключениям. Но в пространстве объектов, подобных исключениям, существует множество вариантов как для семантики или интерфейса, так и для реализации этой семантики.