исключения

Проектирование и разработка идеального средства программирования.

Модератор: Модераторы

исключения

Сообщение bw » 14.10.2007 15:13:40

От хорошей ли жизни появились исключения, точнее механизмы для их обработки и генерирования?
Возможно следует отказаться от директив try, finally, except, raise вообще, либо в пользу обработки ошибок на более "высоком уровне", например за счет переопределения специальных методов класса (я пока использую термин класс, но не обязательно он сохранится :-) или использония других техник на уровне класса.

Можно так:
Код: Выделить всё
type
  MyObject = class
    function MyMethod: Integer;
    function __exception__(error: Exception);
  end;


Или так:
Код: Выделить всё
type
  MyObject = class
    function MyMethod: Integer; except MyExceptionHandler;
  end;

function MyObject.MyExceptionHandler(error: Exception): Integer;
begin
end;


Или так:
Код: Выделить всё
type
  MyObject = class
    function MyMethod: Integer;
  end;

function MyObject.MyMethod: Integer;
begin
  ...
except
  ...
finally
  ...
end;


Что думаете?

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение ev » 14.10.2007 15:37:49

а если надо в одной функции обрабатывать исключения несколько раз?
разносить все по разным процедурам?
ev
долгожитель
 
Сообщения: 1764
Зарегистрирован: 27.04.2005 23:19:06
Откуда: Москва

Сообщение bw » 14.10.2007 16:14:29

Процедура в принципе не должна быть на столько большой что бы еще и вмещать несколько обработчиков исключений. Я считаю что это усложнит код. Еще мне думается что возможность безпрепядственной расстановки ловушек для исключений расслабляет, что ли программиста :-). По идее этот тип ошибок должен быть очень редким и уж точно не появляться несколько раз на метод.
Еще мне кажется можно было бы сделать обработку (фильтрацию или просто уведомление об) исключений тем же объектом, который это исключение генерирует, например для протоколирования, уточнения (к примеру расшифровки кода ошибки или даже замены типа исключений) или проведения анализа состояния объекта и, при необходимости, разрушения самого себя и создания заново :-). Что то вроде реанимации сервера в микроядерной архитектуре. Или это перебор?

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение Sergei I. Gorelkin » 14.10.2007 16:14:57

Основной смысл исключений - это обработка ошибочных ситуаций не в том месте, где они появились, а в другом - которое в точке возникновения ошибки неизвестно. Обработчик ошибок при этом может быть "один на всех". Если же его назначать на каждый метод/класс, указанный смысл теряется начисто.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение bw » 14.10.2007 16:21:53

Можно использовать обработку на уровне класса (т.е. от всех методов) и на уровне конкретного метода:
Код: Выделить всё
type
  A = class
    procedure Foo;
  except E: Exception
    if E.SourceObject is Self then
      WriteLn('Сам виноват') else
      WriteLn('Другой виноват');
    Result := E;
  end;

procedure A.Foo;
begin
  1/0;
except E: Exception
  WriteLn('Что-то случилось');
  Result := E;
end;


Результат работы метода A.Foo:
Код: Выделить всё
Что-то случилось
Сам виноват


..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение bw » 14.10.2007 16:28:27

> это обработка ошибочных ситуаций не в том месте, где они появились, а в другом
Я это знаю :-). Но программисты часто не задумываются об этом, а языки позволяют делать такие ошибки (оборачивать каждое выражение в try-except, да еще в несколько слоев). Я предлагаю ограничить чрезмерное использование обработчиков до одно на метод или даже до одного на класс.
Если и такое удобство, что в связи с отсутствием блока try-except, вложенность (отступами) будет меньше и будет проще читаться. Так же, если ты написал метод без обработки исключений, но в будущем она понадобилась, достаточно дописать в конце метода директиву except, а не добавлять блок try-except, а так же отступы для читаемости кода.

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение Bonart » 15.10.2007 08:07:46

Так. Какие еще классы? Исключения - это реализация структурного перехода "вперед и вверх", как операторы break, continue, exit, только с неизвестным заранее числом уровней. Поэтому привязка исключений к классам и объектам искусственная и ненужная.
Bonart
новенький
 
Сообщения: 81
Зарегистрирован: 29.06.2007 11:47:40

Сообщение bw » 15.10.2007 09:22:06

Искусственная относительно традиционного паскаля? Я не вижу причин почему бы вообще не пересмотреть необходимость исключений, так же как и других конструкция языка. Иначе ничего нового (возможно лучшего) не получится и я продолжу пользоваться существующими языками.

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение Bonart » 15.10.2007 10:45:53

bw
bw писал(а):Искусственная относительно традиционного паскаля?

Искусственная относительно любого языка, кроме тех, в которых классы - принципиальная необходимость (например, Java).
bw писал(а):Я не вижу причин почему бы вообще не пересмотреть необходимость исключений, так же как и других конструкция языка.

Пересмотреть - можно и нужно, чем мы и занимаемся. Всем нам не нравится нынешняя громозкость и непрозрачность записи обработки исключений.
Но жестко привязывать исключения к класса ИМХО нельзя: это концептуально разные, независимые друг от друга вещи - с исключениями можно писать совсем без классов.
Может быть стоит рассмотреть как синтаксически подсластить пилюлю, ведь вложения блоков исключений появились не от хорошей жизни.
Типичный код:
Код: Выделить всё
begin
  Хапаем_ресурсы;
  Используем_ресурсы;
  Отдаем_ресурсы;
end;

Если делать как следует, то будет:
Код: Выделить всё
begin
  try
    try
      Хапаем_ресурсы;
      Используем_ресурсы;
    finally
      Отдаем_ресурсы;
    end;
  except
    Обрабатываем_ошибки;
end;
end;

Получилось некрасиво?
А ведь для начала можно обойтись минимальными изменениями:
Код: Выделить всё
begin
  Хапаем_ресурсы;
  Используем_ресурсы;
finally
  Остдаем_ресурсы;
except
  Обрабатываем_ошибки;
end;

В абсолютном большинстве случаев можно (и нужно!) обойтись только секцией finally.
Bonart
новенький
 
Сообщения: 81
Зарегистрирован: 29.06.2007 11:47:40

Сообщение bw » 15.10.2007 11:03:11

> Но жестко привязывать исключения к класса ИМХО нельзя: это концептуально разные, независимые друг от друга вещи
Это не жесткая привязка, это расширенная запись класса, которая мне показалась удобной и разумной. Я предпочитаю ООП, так что подавляющая часть моего кода состоит из классов и подобные записи в них будут логичными. Так же я предложил дополнить сами методы (функции, процедуры), что может быть применено и в том случае, когда классе не используются.

> с исключениями можно писать совсем без классов.
Но не без методов :-). Исключая блоки инициализации, финализации модулей и главного программного.

> А ведь для начала можно обойтись минимальными изменениями:
Я с этим согласен. Я даже пытался втиснуть секцию с инициализацией данных и гарантированным их освобождение, но в рамках метода получилась чушь:
Код: Выделить всё
method Foo;
vars
  A: AObject;
init
  A := AObject.Create;
body
  A.DivBy(0);
done  {по сути это finally, так же здесь можно вести обработку исключения}
  A.Free;
end;


p.s. Использование секций vars, init и done, конечно же не обязательно. И я не уверен что запись кода в init и done должна быть такой же как и в body, т.е.
Код: Выделить всё
init
  A.Create;
done
  A.Free;

Может оказаться достаточно, т.е. вызываются только деструкторы и конструкторы, например.

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение Bonart » 15.10.2007 11:34:58

bw писал(а):Это не жесткая привязка, это расширенная запись класса, которая мне показалась удобной и разумной. Я предпочитаю ООП, так что подавляющая часть моего кода состоит из классов и подобные записи в них будут логичными. Так же я предложил дополнить сами методы (функции, процедуры), что может быть применено и в том случае, когда классе не используются.

Не очень это удобно - у тебя во все методы вставятся неявные блоки try..except, что крайне неэффективно. Да и неудобно - большинство методов не выбрасывают всех исключений, возможных в классе.
Исключение - средство уровня потока управления, а значит в определении класса вещь чужеродная.
bw писал(а):Исключая блоки инициализации, финализации модулей и главного программного.

Без объектов будут уже не методы, а просто подпрограммы.
bw писал(а):Я с этим согласен. Я даже пытался втиснуть секцию с инициализацией данных и гарантированным их освобождение, но в рамках метода получилась чушь:

Почему чушь? Вполне прилично и куда лучше читается, чем многое другое. Но здесь есть куда пойти дальше, например:
Код: Выделить всё
procedure Foo;
begin
  A := tObject1.Create;
  B := tObject2.Create;
  {Тут код, возможно, генерящий исключение}
done A,B;
  {Тут еще код деинициализации, если надо}
except
  {Тут обработка ошибок, если нужна}
end;

Конструкция body не нужна - она ничего не значит для компилятора. Да и ресурсы могут выделяться по ходу выполнения, а не только в начале.
Bonart
новенький
 
Сообщения: 81
Зарегистрирован: 29.06.2007 11:47:40

Сообщение bw » 15.10.2007 11:43:19

> у тебя во все методы вставятся неявные блоки try..except, что крайне неэффективно
Это не правда, компилятор по наличию директивы может определить использует ли метод обработку исключения и нужно ли его дополнять соответствующим кодом (машинным). Иналичие except в определении класса совершенно не обязательно, так же как и private, protected и т.д.

Код: Выделить всё
done A, B
A и B, это данные которые передаются в секцию, т.е. все остальные определенные в методе не доступны? Или такая запись играет другую роль?

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение Bonart » 15.10.2007 11:58:23

bw писал(а):Это не правда, компилятор по наличию директивы может определить использует ли метод обработку исключения и нужно ли его дополнять соответствующим кодом (машинным).

Слишком много проверок. Особенно если методы вызывают другие методы и т.п. Вдобавок в большинстве промежуточных уровней исключения проверять не надо вообще, ибо хороший тон - обрабатывать ошибки как можно "выше". Не поймет компилятор правильно.
Плюс на разных уровнях одно и то же исключение обрабатывается по-разному: как правило, большая часть кода обработки ошибко неюзабельна за пределами метода, в котором написана.
bw писал(а):A и B, это данные которые передаются в секцию, т.е. все остальные определенные в методе не доступны? Или такая запись играет другую роль?

A и B - это объекты, которые надо грохнуть: зачем записывать A.Free, B.Free и т.д., когда и так понятно что с ними делать в секции finally?
Bonart
новенький
 
Сообщения: 81
Зарегистрирован: 29.06.2007 11:47:40

Сообщение bw » 15.10.2007 12:07:09

> Слишком много проверок.
Статических (при компиляции). Это точно не проблема.

> большая часть кода обработки ошибко неюзабельна за пределами метода, в котором написана
Странно. Вроде обработчик не может и не должен знать где произошла ошибка, разве что только по содержанию самой ошибки (объект Exception). Вообще except в классе стоит рассматривать как обобщающий для всех методов. Как если бы вызов каждого метода производился через одну и ту же подпрограмму, которая могла бы отлавливать исключения.
Так проще было бы контролировать сбойность самого объекта не навешивая обработчиков на каждый метод.

..bw
Аватара пользователя
bw
постоялец
 
Сообщения: 359
Зарегистрирован: 01.12.2005 11:36:23
Откуда: Усть-Илимск

Сообщение Bonart » 15.10.2007 12:21:01

bw
bw писал(а): Как если бы вызов каждого метода производился через одну и ту же подпрограмму, которая могла бы отлавливать исключения.

Так это и есть неявный try..except в каждом методе! По быстродействию полный швах - создавать-убивать по кадру исключений на метод.
bw писал(а):Вроде обработчик не может и не должен знать где произошла ошибка, разве что только по содержанию самой ошибки

Обработчик знает, что ошибка произошла внутри блока, в котором он описан. Где именно внутри - да, не знает.
Но единый обработчик на объект не знает и этого... А действия для разных методов требуются разные!
Bonart
новенький
 
Сообщения: 81
Зарегистрирован: 29.06.2007 11:47:40

След.

Вернуться в Компилятор / язык программирования

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

Рейтинг@Mail.ru
cron