Re[32]: Что вы предлагаете на замену эксепшенов?
От: SleepyDrago Украина  
Дата: 02.12.05 06:45
Оценка:
Здравствуйте, IT, Вы писали:
//код примера красоты работы с исключениями поскипан

Прочитал всю тему и захотелось подлить масла в огонь (пусть я и не согласен с автором темы).
Если я не перепутал то прекрасный пример который мы видели основан на гарантиях небросания
db_connection.rollback()throw()
db_connection.close()throw()
db_connection.~db_connection()throw()

В жизни подобные гарантии эээ "не совсем верны" так ведь ? Насколько я помню дискуссию на clcm по этому поводу
("RAII and resource release functions that can throw" Scott Meyers 20 Фев. 04:26)
в реальном коде обработки банковских транзакций придется ловить все что оттуда вылетает. (те красота в природе не встречается).

И еще один вопросик.
Сдесь была подветка по обработке "нечисел" в формулах и вычислениях. Кто нибудь может показать минимальный пример кода с использованием исключений ? А то создается впечатление что в хендлере верхнего уровня можно "угадать" результат функции по типу "нечисла" которое оттуда вылетело

wbr

Зы все вышесказанное всего лишь мои пять копеек.
Re: Фильтрация исключений
От: Ignoramus  
Дата: 02.12.05 07:23
Оценка: +1
Господа философы, хватит спорить о пользе исключений! Хотел бы затронуть более практическую сторону использования исключений, а именно — фильтрацию. Я уже описывал проблему в форуме С/С++, здесь
Автор: Ignoramus
Дата: 23.11.05
.

Кратко повторюсь. Exception-safe и exception-neutral код действительно очень выигрывает по сравнению с использованием возврата (кода) ошибок.

Однако в программе где-то должны быть (хотя бы один) try/catch, и тут начинаются проблемы. Прежде всего — фильтрация исключений. Исключения могут возникать на разных логических уровнях и смешивать их в кучу нельзя. Например, с нижнего уровня пришло исключение "ошибка переполнения буфера", тогда как пользователю следовало бы показать (да и в лог записать): "не удалось открыть документ, т.к. он открыт другим приложением" (пример чисто условный). Т.е. нужно как бы раскрутить стек в обратную сторону, сверху вниз, чтобы узнать, в какой функции, в какой подфункции и т.д. произошел сбой.

Но стек раскручивается в направлении снизу вверх. Чтобы добиться фильтрации исключений, т.е. подавления исключений нижнего уровня и переизлучения исключений более высокого уровня, необходимо на каждом уровне ставить ловушки try/catch. Например, оборачивать публичные методы классов и конструкторы. Однако при этом код становится менее читабельным и уже больше напоминает проверку кода возврата, т.е. теряет преимущества прозрачности и нейтральности.

Как обычно осуществляют фильтрацию исключений? Может существует какой-то хитрый способ автоматического "оборачивания" исключений на промежуточных уровнях, о котором я не знаю?
Re[2]: Фильтрация исключений
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.12.05 09:09
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Как обычно осуществляют фильтрацию исключений? Может существует какой-то хитрый способ автоматического "оборачивания" исключений на промежуточных уровнях, о котором я не знаю?

Пардон, а чего ты ожидаешь от этого автоматического оборачивания?
В дотнете, к примеру, можно на каждом логическом уровне оборачивать исключения для указания контекста.
Примерно так:
public static Library OpenLibrary(string libId)
{
    #region Arguments validation
  if(libId == null)
      throw new ArgumentNullException("libId");
    #endregion
    try
    {
       return libraries[libId].Open();
    }
    catch(IndexOutOfRange ioor)
    {
      throw new LibraryNotFoundException("specified library not found", libId, ioor);
    }
    catch(Exception e)
    {
      throw new LibraryException("Could not load library with id = " + libId, e);
    }
}

Это означает, что вызывающий код
а) может не заморачиваться с тем, чтобы ловить абстрактные NullReferenceException, который произошел хрен знает где ниже по стеку. Вместо этого можно отлавливать более осмысленные, с его точки зрения, LibraryException и строить на них свою логику (например, попытаться загрузить дефолтную Library, чтобы это ни значило).
б) может получить информацию о причинах проявления высокоуровневого исключения через InnerException. В частности, админ (если от него это не скрыть) сможет понять, что был AccessViolation или FileNotFound.

Да, на первый взгляд это все очень плохо, т.к альтернативой был бы
public static Library OpenLibrary(string libId)
{
     return libraries[libId].Open();
}

который намного короче, яснее, и удобнее в написании. К сожалению, в поддержке подобный код далеко не настолько удобен. К счастью, далеко не всегда нужно писать так много кода.
Как правило речь идет только о фасадном коде, а все внутренние потроха можно оставить в первоначальном виде. Вовсе незачем заворачивать исключение в столько же оберток, сколько методов было на стеке. Обычно обертывание полезно только при пересечении логического уровня.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[28]: Что вы предлагаете на замену эксепшенов?
От: 3axapov  
Дата: 02.12.05 09:47
Оценка:
Здравствуйте, IT, Вы писали:

IT>Да, кстати, использование ref и out параметров считается признаком плохого дизайна. FxCop на это заявляет "Consider a design that does not require that 'parameter_name' be an out parameter".


Если не трудно, нельзя ли раскрыть эту мысль, или носом ткните, где почитать, что плошого в ref и out параметрах?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Фильтрация исключений
От: Ignoramus  
Дата: 02.12.05 10:10
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Ignoramus, Вы писали:


I>>Как обычно осуществляют фильтрацию исключений? Может существует какой-то хитрый способ автоматического "оборачивания" исключений на промежуточных уровнях, о котором я не знаю?

S>Пардон, а чего ты ожидаешь от этого автоматического оборачивания?

Хороший вопрос, я и пытаюсь понять, как бы я хотел чтобы это работало Надеюсь, что вы мне поможете.

S>Это означает, что вызывающий код

S>а) может не заморачиваться с тем, чтобы ловить абстрактные NullReferenceException, который произошел хрен знает где ниже по стеку. Вместо этого можно отлавливать более осмысленные, с его точки зрения, LibraryException и строить на них свою логику (например, попытаться загрузить дефолтную Library, чтобы это ни значило).

Вот-вот, проблема в том, что на уровень функции OpenLibrary подымаются всякие исключения — и абстрактные, и более-менее конкретные. Хотя причины неоткрытия библиотеки вполне конкретные и информативные (например, отсутствует файл, неправильная версия и т.п.), вместо них приходится иметь дело с абстрактными вроде null reference. Ставить на них общую затычку и говорить клиенту "не удалось открыть библиотеку".

S>б) может получить информацию о причинах проявления высокоуровневого исключения через InnerException. В частности, админ (если от него это не скрыть) сможет понять, что был AccessViolation или FileNotFound.


Сможет ли он понять это без раскрутки стека сверху вниз? Точнее, чтобы понять причину сбоя требуется информация от первого метода в стеке, а не последнего, которая приходит.

S>Да, на первый взгляд это все очень плохо, т.к альтернативой был бы

S>который намного короче, яснее, и удобнее в написании. К сожалению, в поддержке подобный код далеко не настолько удобен. К счастью, далеко не всегда нужно писать так много кода.
S>Как правило речь идет только о фасадном коде, а все внутренние потроха можно оставить в первоначальном виде. Вовсе незачем заворачивать исключение в столько же оберток, сколько методов было на стеке. Обычно обертывание полезно только при пересечении логического уровня.

Эта грань между логическими уровнями довольна расплывчата...


Кроме того, меня интересуют следующие проблемы, связанные с исключениями. Интересно было бы услышать комментарии.

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

2) Как следствие из 1), заключение дополнительной информации в исключениях нижнего уровня имеет смысл только в том случае, если предполагается реюзать код нижнего уровня в других проектах. В таком случае, иерархии исключений разных уровней должны быть независимы, точнее нет смысла им быть зависимыми. (хотя первым побуждением есть создание единой иерархии исключений для всего приложения)

3) В каких случаях следует наследовать новый класс исключения от базового, а в каких следует лишь параметризовать его типом/сообщением?

4) Если же требуется транспортировать какое-то сообщение в исключении, как правильно это сделать на практике? Например, как организовать возможность централизованной локализации строк сообщений, загрузку их из ресурсов?
Re[4]: Фильтрация исключений
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.12.05 12:11
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Вот-вот, проблема в том, что на уровень функции OpenLibrary подымаются всякие исключения — и абстрактные, и более-менее конкретные.

Это не так. В данном случае OpenLibrary — это "середина" стека. В нее может приезжать тоже вполне высокоуровневая информация
I>Хотя причины неоткрытия библиотеки вполне конкретные и информативные (например, отсутствует файл, неправильная версия и т.п.), вместо них приходится иметь дело с абстрактными вроде null reference.
Это от того, что предыдущий слой не взял на себя работу по оборачиванию NullReferenceException во что-то более осмысленное.
I>Ставить на них общую затычку и говорить клиенту "не удалось открыть библиотеку".

S>>б) может получить информацию о причинах проявления высокоуровневого исключения через InnerException. В частности, админ (если от него это не скрыть) сможет понять, что был AccessViolation или FileNotFound.


I>Сможет ли он понять это без раскрутки стека сверху вниз? Точнее, чтобы понять причину сбоя требуется информация от первого метода в стеке, а не последнего, которая приходит.

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

I>Эта грань между логическими уровнями довольна расплывчата...

Нет. Если у тебя внятная архитектура, границы между слоями четко очерчены.

I>1) Если все исключения нижнего уровня все равно подавляются на текущем методе и перевыбрасывается одно исключение, свойственное данному уровню и методу, то зачем вкладывать какую-либо информацию в исключения нижнего уровня — она все равно не используется?

Используется!
Еще раз объясняю: пользователю достаточно информации о том, что чего-то сделать не удалось. Админ посмотрит в логи и сможет понять, где не хватило прав (а приложение может лезть в какое-нибудь неожиданное место), где просто убился файл, а где не удалось достучаться до сайта в сети.
I>2) Как следствие из 1), заключение дополнительной информации в исключениях нижнего уровня имеет смысл только в том случае, если предполагается реюзать код нижнего уровня в других проектах. В таком случае, иерархии исключений разных уровней должны быть независимы, точнее нет смысла им быть зависимыми. (хотя первым побуждением есть создание единой иерархии исключений для всего приложения)
Совершенно верно. Иерархии исключений разных слоев не нуждаются в объединении.
I>3) В каких случаях следует наследовать новый класс исключения от базового, а в каких следует лишь параметризовать его типом/сообщением?
Наследоваться имеет смысл в тех случаях, если данный тип исключения имеет смысл ловить отдельным catch(). Трудно сформулировать более точно. Когда ты начнешь писать реальный код, ты сам увидишь, есть ли ситуации, которые ты можешь обработать в рамках данного слоя.
I>4) Если же требуется транспортировать какое-то сообщение в исключении, как правильно это сделать на практике? Например, как организовать возможность централизованной локализации строк сообщений, загрузку их из ресурсов?
Особой нужды в локализации исключений нижнего уровня нет. Локализация исключений, проникающих на уровень UI, делается относительно стандартными средствами: конкретный класс исключения оборудуется конструктором с соответствующими параметрами, берет шаблон строки из ресурсов, и компонует сообщение из шаблона и значений своих параметров.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Фильтрация исключений
От: Ignoramus  
Дата: 02.12.05 13:05
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Это от того, что предыдущий слой не взял на себя работу по оборачиванию NullReferenceException во что-то более осмысленное.


Т.е. в промышленном коде именно так и делают? Оборачивают на каждом уровне? Как именно выглядит это оборачивание — в самом начале каждого публичного метода и конструктора ставится try, а в самом конце catch с пере-throw? Иначе я не вижу способа обеспечить полный отлов всех исключений в целях их оборачивания.

S>Используется!

S>Еще раз объясняю: пользователю достаточно информации о том, что чего-то сделать не удалось. Админ посмотрит в логи и сможет понять, где не хватило прав (а приложение может лезть в какое-нибудь неожиданное место), где просто убился файл, а где не удалось достучаться до сайта в сети.

При условии присутствия промежуточных оборачивателей — да. Я пытался выяснить можно ли обойтись одним try/catch на верхнем уровне и при этом получать более подробную информацию о сбое. По-видимому это невозможно .

S>Совершенно верно. Иерархии исключений разных слоев не нуждаются в объединении.


Интересно, а где лучше размещать описания классов исключений? Наверное в том же пространстве имен, что и "логический уровень", все классы которого бросают одни и те же исключения? Не выделять в отдельный namespace Exceptions?

I>>4) Если же требуется транспортировать какое-то сообщение в исключении, как правильно это сделать на практике? Например, как организовать возможность централизованной локализации строк сообщений, загрузку их из ресурсов?

S>Особой нужды в локализации исключений нижнего уровня нет. Локализация исключений, проникающих на уровень UI, делается относительно стандартными средствами: конкретный класс исключения оборудуется конструктором с соответствующими параметрами, берет шаблон строки из ресурсов, и компонует сообщение из шаблона и значений своих параметров.

А как тогда анализировать причину сбоя и выводить пользователю инфу, если она приходит с нижнего нелокализованного уровня? Может тогда вообще отказаться от текста и идентифицировать исключения нижнего уровня только по их типу, а соответствующий текст добавлять в верхнем уровне? Или это нарушает инкапсуляцию исключений?
Re[6]: Фильтрация исключений
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.12.05 13:27
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Т.е. в промышленном коде именно так и делают? Оборачивают на каждом уровне?

Да.
I>Как именно выглядит это оборачивание — в самом начале каждого публичного метода и конструктора ставится try, а в самом конце catch с пере-throw?
Нет. Не каждого публичного метода. При пересечении границы слоев. Сколько слоев в твоей архитектуре?
I>Иначе я не вижу способа обеспечить полный отлов всех исключений в целях их оборачивания.
I>При условии присутствия промежуточных оборачивателей — да. Я пытался выяснить можно ли обойтись одним try/catch на верхнем уровне и при этом получать более подробную информацию о сбое. По-видимому это невозможно .
Действительно, практически невозможно. Принципиальным ограничением является отсутствие информации о контексте. Современные управляемые среды уже предоставляют гораздо больше информации, чем это было возможно раньше — в частности, call stack. К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную".
I>Интересно, а где лучше размещать описания классов исключений? Наверное в том же пространстве имен, что и "логический уровень", все классы которого бросают одни и те же исключения? Не выделять в отдельный namespace Exceptions?
Наверное, да. Хотя принципиальной разницы нет — просто удобнее пользоваться, когда для исключений не нужно подключать отдельный namespace.

I>А как тогда анализировать причину сбоя и выводить пользователю инфу, если она приходит с нижнего нелокализованного уровня? Может тогда вообще отказаться от текста и идентифицировать исключения нижнего уровня только по их типу, а соответствующий текст добавлять в верхнем уровне? Или это нарушает инкапсуляцию исключений?

Не нарушает. Информация нижнего уровня все равно читается технически квалифицированными людьми, которые в состоянии понять "File Not Found" независимо от их родного языка.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Фильтрация исключений
От: Ignoramus  
Дата: 02.12.05 13:41
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Ignoramus, Вы писали:


S>Нет. Не каждого публичного метода. При пересечении границы слоев. Сколько слоев в твоей архитектуре?


Хотел бы я это знать, черт побери! Наверное 3... или 4

Однако же, под "публичными" я имел в виду методы, которые вызываются более верхним слоем (а не просто объявленные как public) С этой поправкой мое утверждение верно?

I>>Иначе я не вижу способа обеспечить полный отлов всех исключений в целях их оборачивания.

I>>При условии присутствия промежуточных оборачивателей — да. Я пытался выяснить можно ли обойтись одним try/catch на верхнем уровне и при этом получать более подробную информацию о сбое. По-видимому это невозможно .
S>Действительно, практически невозможно. Принципиальным ограничением является отсутствие информации о контексте. Современные управляемые среды уже предоставляют гораздо больше информации, чем это было возможно раньше — в частности, call stack. К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную".

Как теоретический вариант я рассматривал возможность при получении исключения на верхнем уровне "подсмотреть" в стек, чтобы узнать от какого метода более низкого уровня пришло данное исключение. Если предположить, что каждый "публичный" метод выполняет только одну ф-цию и соответственно переизлучал бы только одно исключение (если бы в нем был оборачиватель), таким образом можно определить причину сбоя, без промежуточных оборачивателей. Бред?

I>>А как тогда анализировать причину сбоя и выводить пользователю инфу, если она приходит с нижнего нелокализованного уровня? Может тогда вообще отказаться от текста и идентифицировать исключения нижнего уровня только по их типу, а соответствующий текст добавлять в верхнем уровне? Или это нарушает инкапсуляцию исключений?

S>Не нарушает. Информация нижнего уровня все равно читается технически квалифицированными людьми, которые в состоянии понять "File Not Found" независимо от их родного языка.

Уточню вопрос: использовать ли вообще строки в исключениях нижнего уровня или достаточно их типа, а весь текст обеспечивается верхним уровнем на основании этого типа?
Re[7]: Фильтрация исключений
От: Cyberax Марс  
Дата: 02.12.05 13:42
Оценка:
Sinclair wrote:

> Современные управляемые среды уже предоставляют гораздо больше

> информации, чем это было возможно раньше — в частности, call stack. К
> сожалению, пока что нет возможности автоматически получить информацию
> об а) значениях параметров в стеке

Управляемые среды — ацтой

Вообще-то в MS VС++ вполне можно получить stacktrace, значения
аргументов, и даже значения переменных в фреймах функций. Единственное
что нужно — это иметь PDB-файл.

В управляемые среды такое добавить сильно больших сложностей не должно
представить. Вероятно это пока никому не надо, или просто еще не
додумались добавить.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[7]: Фильтрация исключений
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 02.12.05 13:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную".


Возможность такая, естественно, есть. В каких системах — не трудно догадаться Другое дело, что, для автоматического перезаворачивания исключений, особого толку от состояния объектов и значений параметров я не вижу.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[8]: Фильтрация исключений
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.12.05 13:54
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Уточню вопрос: использовать ли вообще строки в исключениях нижнего уровня или достаточно их типа, а весь текст обеспечивается верхним уровнем на основании этого типа?


Использовать. Часто бывает, что сохраненная на самом низком уровне полная информация о причине исключения оказывается очень важной при разборе полетов. Терять такую информацию, если она есть, глупо. В частности, крайне полезным бывает сохранение значения errno.

Не обязательно это могут быть строки. Например, мне иногда приходится порождать исключения при выходе за пределы блока с десериализуемыми данными. Тогда я располагаю информацией о: размере буфера, текущей позиции в буфере и количеством байт, которые хотят прочитать. Для этого в С++ можно использовать, что-то вроде:
class bound_ex_t : public std::exception
    {
    private :
        size_t    m_buf_size;
        size_t    m_pos;
        size_t    m_required_size;
        
        //! Для того, чтобы можно было сформировать в what().
        mutable std::string m_what;
        
    public :
        bound_ex_t( size_t buf_size, size_t pos, size_t required_size )
            :    m_buf_size( buf_size ), m_pos( pos ), m_required_size( required_size )
            {}
            
        virtual const char * what() const
            {
                if( m_what.empty() )
                    {
                        <создание строки с описанием всей доступной информации>
                    }
                return m_what.c_str();
            }
    };


bound_ex_t::m_what можно формировать и в конструкторе bound_ex_t, только зачем это делать сразу, если what() у нас могут и не вызвать вообще.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Фильтрация исключений
От: Ignoramus  
Дата: 02.12.05 14:11
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Ignoramus, Вы писали:


I>>Уточню вопрос: использовать ли вообще строки в исключениях нижнего уровня или достаточно их типа, а весь текст обеспечивается верхним уровнем на основании этого типа?


E>Использовать. Часто бывает, что сохраненная на самом низком уровне полная информация о причине исключения оказывается очень важной при разборе полетов. Терять такую информацию, если она есть, глупо. В частности, крайне полезным бывает сохранение значения errno.


Кстати о номерах ошибок. Идея конечно заманичвая, но ее основной недостаток, по моему опыту, это необходимость консистентной нумерации ошибок во всем приложении, во всех уровнях архитектуры. Это лишняя связь, и довольно-таки напрягает имхо. Может поэтому в std::exception есть строковый what, а не числовой
Re[7]: Фильтрация исключений
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 02.12.05 14:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Действительно, практически невозможно. Принципиальным ограничением является отсутствие информации о контексте. Современные управляемые среды уже предоставляют гораздо больше информации, чем это было возможно раньше — в частности, call stack. К сожалению, пока что нет возможности автоматически получить информацию об а) значениях параметров в стеке и б) состоянии объектов. Прежде всего потому, что такая возможность вызвала бы существенное понижение быстродействия "безошибочных" приложений. В принципе, можно ожидать появления подобных возможностей в следующих поколениях управляемых систем. Пока что нам остается следовать приведенным соображениям "вручную".


Современные управляемые среды всё это умели делать давным давно. Вот смотрите, ниже я привожу пример стека со всеми локальными переменными процедур и полями объектов, причем каждый пункт — это гиперссылка на соответствующую позицию в исходном тексте программы.

Фрагмент:



Сама программа:

MODULE TestException;

  IMPORT StdLog, Math;

  TYPE
    MyObject = RECORD
      x, y, z: REAL
    END;
    
  PROCEDURE Sqrt (x : REAL): REAL;
  BEGIN ASSERT(x >= 0.0, 20);
    RETURN Math.Sqrt(x)
  END Sqrt;
  
  PROCEDURE Do*;
    VAR obj: MyObject;
    a, b, c: REAL;
  BEGIN
    a := 111.0;
    b := 222.0;
    c := 333.0;
    obj.x := 444.0;
    obj.y := 555.0;
    obj.z := 666.0;
    c := Sqrt(-777.0);
    StdLog.Real(c)
  END Do;
  
END TestException.


Полная развертка стека (при конвертации в plain text специальные view, естественно, исчезли):
TRAP 20  (precondition violated)

 TestException.Sqrt   [0000001FH] 
    .x    REAL    -777.0
 TestException.Do   [00000095H] 
    .a    REAL    111.0
    .b    REAL    222.0
    .c    REAL    333.0
    .obj    TestException.MyObject    fields
 StdInterpreter.CallProc   [000003A5H] 
    .a    BOOLEAN    FALSE
    .b    BOOLEAN    FALSE
    .c    BOOLEAN    FALSE
    .i    Meta.Item    fields
    .imported    ARRAY 256 OF CHAR    ""   ...
    .importing    ARRAY 256 OF CHAR    ""   ...
    .mn    Meta.Name    "TestException"
    .mod    StdInterpreter.Ident    "TestException"
    .object    ARRAY 256 OF CHAR    ""   ...
    .ok    BOOLEAN    TRUE
    .parType    INTEGER    0
    .pn    Meta.Name    "Do"
    .proc    StdInterpreter.Ident    "Do"   ...
    .res    INTEGER    0
    .v    StdInterpreter.ProcVal    fields
    .vi    StdInterpreter.ProcIVal    fields
    .vii    StdInterpreter.ProcIIVal    fields
    .vr    StdInterpreter.ProcRVal    fields
    .vri    StdInterpreter.ProcRIVal    fields
    .vrii    StdInterpreter.ProcRIIVal    fields
    .vrr    StdInterpreter.ProcRRVal    fields
    .vrri    StdInterpreter.ProcRRIVal    fields
    .vrrii    StdInterpreter.ProcRRIIVal    fields
    .vrs    StdInterpreter.ProcRSVal    fields
    .vrsi    StdInterpreter.ProcRSIVal    fields
    .vrsii    StdInterpreter.ProcRSIIVal    fields
    .vs    StdInterpreter.ProcSVal    fields
    .vsi    StdInterpreter.ProcSIVal    fields
    .vsii    StdInterpreter.ProcSIIVal    fields
    .vsr    StdInterpreter.ProcSRVal    fields
    .vsri    StdInterpreter.ProcSRIVal    fields
    .vsrii    StdInterpreter.ProcSRIIVal    fields
    .vss    StdInterpreter.ProcSSVal    fields
    .vssi    StdInterpreter.ProcSSIVal    fields
    .vssii    StdInterpreter.ProcSSIIVal    fields
 StdInterpreter.Command   [00001260H] 
    .left    StdInterpreter.Ident    "TestException"
    .ptype    INTEGER    0
    .right    StdInterpreter.Ident    "Do"   ...
 StdInterpreter.CallHook.Call   [00001385H] 
    .ch    CHAR    0X
    .e    ARRAY 64 OF CHAR    ""   ...
    .errorMsg    ARRAY 2 OF CHAR    " "
    .f    ARRAY 64 OF CHAR    ""   ...
    .g    ARRAY 64 OF CHAR    ""   ...
    .hook    StdInterpreter.CallHook    [0105F190H] 
    .i    INTEGER    17
    .i0    INTEGER    0
    .i1    INTEGER    0
    .id    StdInterpreter.Ident    "Do"   ...
    .par0    Dialog.String    ""   ...
    .par1    Views.Title    ""   ...
    .proc    ARRAY 256 OF CHAR    "TestException.Do"   ...
    .res    INTEGER    0
    .s0    Dialog.String    ""   ...
    .s1    Dialog.String    ""   ...
    .type    INTEGER    3
    .x    INTEGER    0
 Dialog.Call   [00003266H] 
    .errorMsg    ARRAY 2 OF CHAR    " "
    .proc    ARRAY 256 OF CHAR    "TestException.Do"   ...
    .res    INTEGER    0
 DevCommanders.Execute   [00000662H] 
    .beg    INTEGER    439
    .cmd    Dialog.String    "TestException.Do"   ...
    .end    INTEGER    440
    .pos    INTEGER    423
    .res    INTEGER    0
    .s    DevCommanders.Scanner    fields
    .t    TextModels.Model    [010FB6C0H] 
    .unload    BOOLEAN    TRUE
 DevCommanders.Track   [00000795H] 
    .buttons    SET    {2, 16, 25}
    .c    Models.Context    [01188A90H] 
    .end    INTEGER    440
    .f    Views.Frame    [0100A720H] 
    .h    INTEGER    152400
    .in    BOOLEAN    TRUE
    .in0    BOOLEAN    TRUE
    .isDown    BOOLEAN    FALSE
    .m    SET    {2, 25}
    .v    DevCommanders.View    [01018DF0H] 
    .w    INTEGER    177800
    .x    INTEGER    98425
    .y    INTEGER    69850
 DevCommanders.StdView.HandleCtrlMsg   [00000946H] 
    .f    Views.Frame    [0100A720H] 
    .focus    Views.View    NIL
    .msg    Controllers.TrackMsg    fields
    .v    DevCommanders.StdView    [01018DF0H] 
 Views.ForwardCtrlMsg   [000026B0H] 
    .a    Views.View    NIL
    .f    Views.Frame    [0100A720H] 
    .focus    Views.View    NIL
    .g    Views.Frame    [010233E0H] 
    .h    Views.Frame    NIL
    .msg    Controllers.TrackMsg    fields
    .op    INTEGER    1
    .req    BOOLEAN    FALSE
    .v    Views.View    [01018DF0H] 
 Views.ForwardCtrlMsg   [0000276BH] 
    .a    Views.View    NIL
    .f    Views.Frame    [010233E0H] 
    .focus    Views.View    [01018DF0H] 
    .g    Views.Frame    [01019830H] 
    .h    Views.Frame    [0100A720H] 
    .msg    Controllers.TrackMsg    fields
    .op    INTEGER    1
    .req    BOOLEAN    FALSE
    .v    Views.View    [01018D30H] 
 Views.ForwardCtrlMsg   [0000276BH] 
    .a    Views.View    NIL
    .f    Views.Frame    [01019830H] 
    .focus    Views.View    [01018D30H] 
    .g    Views.Frame    NIL
    .h    Views.Frame    [010233E0H] 
    .msg    Controllers.TrackMsg    fields
    .op    INTEGER    1
    .req    BOOLEAN    FALSE
    .v    Views.View    [010FC860H] 
 Windows.Window.ForwardCtrlMsg   [000002AFH] 
    .msg    Controllers.TrackMsg    fields
    .w    Windows.Window    [010192D0H] 
 HostWindows.Window.ForwardCtrlMsg   [00001615H] 
    .d    BOOLEAN    FALSE
    .msg    Controllers.TrackMsg    fields
    .res    INTEGER    2010420391
    .w    HostWindows.Window    [010192D0H] 
 HostWindows.Window.MouseDown   [00001BA5H] 
    .modifiers    SET    {2, 16, 25}
    .ph    INTEGER    504
    .pw    INTEGER    656
    .time    INTEGER    0
    .track    Controllers.TrackMsg    fields
    .w    HostWindows.Window    [010192D0H] 
    .x    INTEGER    17
    .y    INTEGER    398
 HostWindows.HandleMouse   [0000343DH] 
    .b    SET    {2, 16, 25}
    .f    Views.Frame    NIL
    .g    Views.Frame    NIL
    .isDown    BOOLEAN    TRUE
    .lParam    INTEGER    26083345
    .w    HostWindows.Window    [010192D0H] 
    .wParam    INTEGER    265
    .wnd    INTEGER    590618
    .x    INTEGER    17
    .y    INTEGER    398
 Kernel.Try   [00003A31H] 
    .a    INTEGER    590618
    .b    INTEGER    265
    .c    INTEGER    26083345
    .h    PROCEDURE    HostWindows.HandleMouse
 HostWindows.DocWinHandler   [00003FA3H] 
    .dx    INTEGER    0
    .dy    INTEGER    1953697393
    .lParam    INTEGER    26083345
    .message    INTEGER    513
    .res    INTEGER    0
    .st    SET    {2}
    .style    SET    {1, 2, 16, 18}
    .w    HostWindows.Window    NIL
    .wParam    INTEGER    9
    .wnd    INTEGER    590618
    .x    INTEGER    2147348480
<system>   (pc=77D48708H,  fp=0022FB84H)
<system>   (pc=77D487EAH,  fp=0022FBECH)
<system>   (pc=77D489A4H,  fp=0022FC4CH)
<system>   (pc=77D4BCCBH,  fp=0022FC5CH)
 HostMenus.Loop   [00003C52H] 
    .done    BOOLEAN    FALSE
    .f    SET    {0..5}
    .n    INTEGER    0
    .res    INTEGER    0
    .w    HostWindows.Window    NIL
 Kernel.Start   [00002B5CH] 
    .code    PROCEDURE    HostMenus.Loop
Re[10]: Фильтрация исключений
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.12.05 14:44
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Кстати о номерах ошибок. Идея конечно заманичвая, но ее основной недостаток, по моему опыту, это необходимость консистентной нумерации ошибок во всем приложении, во всех уровнях архитектуры. Это лишняя связь, и довольно-таки напрягает имхо. Может поэтому в std::exception есть строковый what, а не числовой


Я ведь не предлагал вводить собственную систему номеров ошибок, а сохранять, где это имеет смысл, значение errno. А за консистентность нумерации ошибок в errno стандартная (и не только) библиотека отвечает. На Windows так же можно и GetLastError использовать при работе с WinAPI.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[8]: Фильтрация исключений
От: AndrewJD США  
Дата: 02.12.05 16:31
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Вообще-то в MS VС++ вполне можно получить stacktrace, значения

C>аргументов, и даже значения переменных в фреймах функций. Единственное
C>что нужно — это иметь PDB-файл.

От PDB файла не всегда много толку, если включена агресивная оптимизация и Frame-Pointer Omission.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[20]: error is not an exception
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.12.05 00:34
Оценка:
Cyberax wrote:
>
> ASSERT'ы — это НЕ мусор. Это чрезвычайно удобное средство отладки.

Более того, хорошо поставленный assert помогает защитить свой код от
лазанья в него "умелыми ручками" всяких разных других участников проекта
— из того числа, которые могут позвать любую обнаруженную ими функцию в
любом контексте, и не читают комментариев.

Без ассерта это кончится тем, что "что-то твой код глючит". С ассертом
диалог будет примерно следующий: "что-то у тебя ассерт срабатывает" —
"до твоей правки не срабатывал" — "а как тогда мне сделать XXX?". И вот
с этого последнего вопроса можно уже начинать нормальный диалог...
Posted via RSDN NNTP Server 2.0
Re[21]: error is not an exception
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.12.05 00:36
Оценка:
IT wrote:
>
> C>Или, например, вот такой код (спас часы отладки):
>
> Так может такие проверки должны быть штатными и использоваться не только
> в режиме отладки?

Да, безусловно. Ассерты должны оставаться в релизе. Надо только
придумать, как сделать так, чтобы последние слова программы попали таки
тебе в руки вместе с bag report'ом.
Posted via RSDN NNTP Server 2.0
Re[22]: error is not an exception
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.12.05 00:37
Оценка:
Глеб Алексеев wrote:
>
> IT>Так может такие проверки должны быть штатными и использоваться не
> только в режиме отладки?
> Зачем, если они срабатывают только при наличии ошибки в программе (и
> теоретически в окончательной версии их быть не должно) и могут снижать
> производительность?

Потому, что даже в релизнутой программе могут остаться ошибки. И лучше,
чтобы последние слова упавшей программы были осмысленными, чем просто
слепой GPF.
Posted via RSDN NNTP Server 2.0
Re[22]: error is not an exception
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.12.05 00:39
Оценка:
Cyberax wrote:
>
> А зачем? assert показывает ошибки программиста, а не пользователя. То
> есть ни при каком варианте работы событий пользователь не должен его
> получить, а значит и включать его не надо.
>
> В рельной жизни assert'ы обычно оставляют в бэта-версиях, и выкидывают в
> релизах.

А что, в релизах каким-то волшебным образом нет ни одной ощибки?

Какая альтернатива существует у программы, которая вошла в состояние,
когда должен бы сработать assert, а assert-а то и нету? Только сойти с
ума, и в лучшем случае упасть на GPF'е. А в худшем — безнадежно
испортить пользовательские файлы.
Posted via RSDN NNTP Server 2.0
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.