> -- Цитата:
> Нет, я имел в виду другоеНу например так:
Если я правильно вас понял, вы ASSERT-ы считаете ошибками? Я расцениваю ASSERT как категорическое утверждение, которое нельзя отловить и обработать. В вашем примере процедуры E2 предположим, что функции возвращают код ошибки (0 - всё хорошо). Тогда помогает простое разбиение на подпроцедуры:

## Код:
```
PROCEDURE E2;
  PROCEDURE Sub2: BOOLEAN;
  BEGIN
    RESULT:=OK;
    WHILE RESULT = OK DO
      RESULT:=Sub4;
    END;
  END;

  ...SubN...

BEGIN
  RESULT:=BAD;
  IF
    Sub1 AND
    Sub2 AND
    Sub3
  THEN
    RESULT:=OK;
  END;
END E2;
```


Пример из реального кода привожу. К сожалению, не сохранил исходников до переработки, когда это были break-и, вложенные циклы и т.д. Переписывая код в структурном стиле, понял, что будет огромное кол-во условий и внутренних IF. Решение: декомпозиция.

## Код:
```
PROCEDURE SelectLanguage (CONST LangName: STRING);
...
   (* SetLngFromRes *) {Пробует найти языковые данные в ресурсах}
   FUNCTION SetLngFromRes (Client: TClient; CONST LangName: STRING): BOOLEAN;
   ...
   END; // .function SetLngFromRes
   
   (* SetLngFromFilePack *) {Пробует загрузить файловый пак и найти там языковые данные}
   FUNCTION SetLngFromFilePack (Client: TClient; CONST LangName: STRING): BOOLEAN;
   BEGIN
   ...
   END; // .function SetLngFromFilePack
   
   (* SetLngFromFileUnit *) {Пробует загрузить файловый модуль и найти там языковые данные}
   FUNCTION SetLngFromFileUnit (Client: TClient; CONST LangName: STRING): BOOLEAN;
   BEGIN
   ...
   END; // .function SetLngFromFileUnit
   
   (* SetLngFromFileStrings *) {Пробует загрузить файловые строки с нужными языковыми данными}
   FUNCTION SetLngFromFileStrings (Client: TClient; CONST LangName: STRING): BOOLEAN;
   BEGIN
   ...
   END; // .function SetLngFromFileStrings
   
BEGIN
   ...
   FOR i:=0 TO Clients.Count - 1 DO BEGIN
      Client:=TClient(Clients.Objects[i]);
      IF Client.Language <> LangName THEN BEGIN
         // Смотрим, не является ли выбираемый язык языком по умолчанию для модуля
         IF Client.DefLangName = LangName THEN BEGIN
         ...
         END // .if
         ELSE IF
            (NOT SetLngFromRes(Client, LangName)) AND
            (NOT SetLngFromFilePack(Client, LangName)) AND
            (NOT SetLngFromFileUnit(Client, LangName))
         THEN BEGIN
            SetLngFromFileStrings(Client, LangName);
         END; // .elseif
      END; // .if
   END; // .for
END; // .procedure SelectLanguage
```


Эти строки:
> -- Цитата:
> (NOT SetLngFromRes(Client, LangName)) AND(NOT SetLngFromFilePack(Client, LangName)) AND(NOT SetLngFromFileUnit(Client, LangName))...SetLngFromFileStrings(Client, LangName);
содержат, фактически, основной код, вложенные циклы, сложные условия. Как видно, после декомпозиции проблемы не стало.

Возвращая коды ошибок, вы предоставляете право функциям верхнего уровня самим решать, как обрабатывать ошибки, и стоит ли их обрабатывать.

В чём по вашему структурность программы, если из произвольного блока можно сделать произвольный вылет, который вернётся только где-то там на одном из верхних уровней в установленным когда-то обработчике? Программист больше не уверен в целостности конструкций IF-ELSE, WHILE, PROCEDURE END и т.д. Какие инварианты и доказательства программ? Может кому-то и проще писать:

## Код:
```
TRY
много вызовов опасного кода без разбора
FINALLY
...
END;
```


...как советует Влад. А в чём тогда смысл вызыва исключения, если его можно таким образом тихо подавить и даже не знать, что там было и почему? Может быть причина ошибки - код программы, а не внешние условия.
В истинно структурном коде, если мы откроем файл без проверки результата, то ничего не произойдёт. А вот вызов FileRead встретит ASSERT(Handle <> INVALID_HANDLE_VALUE) и такой ассерт просто нельзя подавлять. А у вас можно написать где-то там далеко TRY FINALLY и забыть про ошибки вообще. Но они всплывут, а ваша программа не станет безопаснее.

Чтобы обсудить вопрос более формально, приведу три "теоремы":

I.
Пусть любая функция, чей результат может быть неуспешен, возвращает либо BOOLEAN либо INTEGER как флаг ошибки. При этом для INTEGER 0 - нет ошибки, MAX(INTEGER) - неизвестная ошибка, а множество (0; MAX(INTEGER)) - множество кодов ошибок. Тогда любой код, где вы предлагаете использовать обработку исключений, сравнительно легко переписывается в структурном стиле без обработки исключений.

II.
Если в функции каждое последующее действие требует успешного результата предыдущего, а число действий велико, то код функции разбивается на подфункции так, что кол-во действий находилось в рамках 1-7.

III.Структурный код - это код, не содержащий никаких операторов выхода из текущего блока, а именно: BREAK/CONTINUE/EXIT/RETURN/RAISE.

"Выполнение условного оператора if"


В Обероне не 2007/ББ есть два нарушения, позволяющих писать неструктурный код: RETURN из произвольного места процедуры и LOOP EXIT.

> -- Википедия писал(а):
> Структурное программирование — методология разработки программного обеспечения, в основе которой лежит представление программы в виде иерархической структуры блоков. Предложена в 70-х годах XX века Э. Дейкстрой, разработана и дополнена Н. Виртом.В соответствии с данной методологиейЛюбая программа представляет собой структуру, построенную из трёх типов базовых конструкций: -)  — однократное выполнение операций в том порядке, в котором они записаны в тексте программы;-)  — однократное выполнение одной из двух или более операций, в зависимости от выполнения некоторого заданного условия;-)  — многократное исполнение одной и той же операции до тех пор, пока выполняется некоторое заданное условие (условие продолжения цикла).В программе базовые конструкции могут быть вложены друг в друга произвольным образом, но никаких других средств управления последовательностью выполнения операций не предусматривается.Повторяющиеся фрагменты программы (либо не повторяющиеся, но представляющие собой логически целостные вычислительные блоки) могут оформляться в виде т. н. подпрограмм (процедур или функций). В этом случае в тексте основной программы, вместо помещённого в подпрограмму фрагмента, вставляется инструкция вызова подпрограммы. При выполнении такой инструкции выполняется вызванная подпрограмма, после чего исполнение программы продолжается с инструкции, следующей за командой вызова подпрограммы.Разработка программы ведётся пошагово, методом «сверху вниз».