OberonCore https://forum.oberoncore.ru/ |
|
Оцените механизм исключений в PureBuilder https://forum.oberoncore.ru/viewtopic.php?f=93&t=3235 |
Страница 2 из 2 |
Автор: | Александр Шостак [ Воскресенье, 06 Февраль, 2011 20:03 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Кажется, я вас наконец-то понял. Мой вариант: функция возвращает флаг результата, а значение в OUT-параметре. Если нужна более детализированная информация об ошибке, то ещё один аргумент - сама ошибка. Таким образом количество аргументов функции увеличивается на 1-2. Плюсы: +) Сохраняется правило: у блока один вход и один выход, а с ним и все формальные доказательства о свойствах кода. +) Функции унифицированны. Не нужно знать имён исключений или расшифровывать мета-информацию в результатах. TRUE - успех, FALSE - нет. +) Любые естественные логические выражения легко строятся из функций, не возвращающих гарантированно результат (если удалость А и удалось Б или не удалось С, то попробовать Д или Е). -) Лишние параметры, что кажется громоздким. -) Непривычный и громоздкий стиль использования результата функции в качестве аргумента. Ранее: A(B(C())); Теперь: A(ResA) AND B(ResA, ResB) AND C(ResB, ResC); Ваш вариант. Конструкция catch относится к вызывающей процедуре. +) Функции сохраняют свой естественный вид. *) Структурность нарушается лишь частично - на одном уровне. ?) PureBuilder поддерживает выражения из функций? К какой части выражения тогда относится catch? catch может быть применён к целому блоку кода? -) Если catch не применяем к блоку кода, то отсутствует возможность последовательного условного выполнения функций, которое встречается очень часто: A; B; C; catch // хотели попадать сюда, если A, B или C завершилось не успешно. end; Аналог: Result:=A AND B AND C; -) У catch нет ветки else/elseif, так что развилка естественным образом не пишется: Код: IF StrPos(...) THEN // если нашли подстроку, то один код
... ELSE // другой код ... END; StrPos(...); catch ... // код обработки исключения без развилки end; |
Автор: | Сергей Прохоренко [ Воскресенье, 06 Февраль, 2011 23:20 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Александр Шостак писал(а): Мой вариант: ... Плюсы: +) Сохраняется правило: у блока один вход и один выход, а с ним и все формальные доказательства о свойствах кода. Разве свойства кода в PureBuilder менее понятны? А вот сигнальные значения функции несут в себе опасности:
Александр Шостак писал(а): +) Функции унифицированны. Не нужно знать имён исключений или расшифровывать мета-информацию в результатах. TRUE - успех, FALSE - нет. Аналогичная по функциональности вещь будет в PureBuilder - это универсальный блок catch exception, который будет работать при любом исключении. Я о нем уже думал раньше, но пока не успел добавить на сайт. Остальные блоки catch имя исключения программист может не заполнять, если в этом нет необходимости. Александр Шостак писал(а): +) Любые естественные логические выражения легко строятся из функций, не возвращающих гарантированно результат (если удалость А и удалось Б или не удалось С, то попробовать Д или Е). Я за жесткое разделение штатного и аварийного алгоритмов, поэтому мне не нравится такой подход. Но то, что Вы описываете, можно сделать и в PureBuilder, задав необходимые значения флагов в разных блоках catch. Александр Шостак писал(а): Ваш вариант. Конструкция catch относится к вызывающей процедуре. *) Структурность нарушается лишь частично - на одном уровне. Я не вижу, чтобы она вообще нарушалась. Блоки catch выбираются в зависимости от имени исключения - аналогично действию оператора switch/case, который самый что ни на есть "структурный". Александр Шостак писал(а): ?) PureBuilder поддерживает выражения из функций? Да. Александр Шостак писал(а): К какой части выражения тогда относится catch? К любой, вызвавшей исключение. Александр Шостак писал(а): catch может быть применён к целому блоку кода? Нет. Только к одному оператору присваивания, вызова процедуры, ввода/вывода или размещения в памяти, то есть, к любому оператору, который может непосредственно сгенерировать исключение. Но catch не может быть применён к условному оператору, оператору цикла и т.п. |
Автор: | Александр Шостак [ Воскресенье, 06 Февраль, 2011 23:54 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Цитата: Я не вижу, чтобы она вообще нарушалась. Блоки catch выбираются в зависимости от имени исключения - аналогично действию оператора switch/case, который самый что ни на есть "структурный". Там, где вызывается throw/escape, которые в вашей реализации эквивалентны return из произвольного места функции. В результате функция уже не блок с одним входом и одним выходом. Я не говорю, что это катастрофично, но и не поддерживаю такой подход. Понадобится доработать функцию, добавив предвыходные действия, и подобные throw из середины уже мешают. |
Автор: | Сергей Прохоренко [ Понедельник, 07 Февраль, 2011 00:15 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Александр Шостак писал(а): Цитата: Я не вижу, чтобы она вообще нарушалась. Блоки catch выбираются в зависимости от имени исключения - аналогично действию оператора switch/case, который самый что ни на есть "структурный". Там, где вызывается throw/escape, которые в вашей реализации эквивалентны return из произвольного места функции. В результате функция уже не блок с одним входом и одним выходом. Я не говорю, что это катастрофично, но и не поддерживаю такой подход. Понадобится доработать функцию, добавив предвыходные действия, и подобные throw из середины уже мешают. Оператор throw служит только для отладки и не применяется в рабочей программе. Поэтому считайте его комментарием. Комментарии ведь не нарушают структурность. В отличие от escape он находится в той же процедуре/функции, что и блоки catch. Оператор escape завершает функцию/процедуру без возврата каких-либо данных (кроме имени исключения) в точку вызова. Они не возвращаются потому, что недостоверны (иначе механизм исключений не должен применяться). В каком бы месте функции ни происходил выход, данные не станут достоверными. Поэтому бессмысленно беспокоиться о том, что не были исполнены операторы после оператора escape до конца процедуры/функции. Никакая доработка функции не требуется. |
Автор: | Александр Шостак [ Понедельник, 07 Февраль, 2011 00:35 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Данные недостоверны - отлично. Но хотелось бы закрыть дескрипторы, вызвать деструкторы, обнулить кое-какие поля в структурах. Иными словами - привести систему в исходное состояние до выова подпрограммы. Такое возможно? |
Автор: | Сергей Прохоренко [ Понедельник, 07 Февраль, 2011 21:56 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Александр Шостак писал(а): Данные недостоверны - отлично. Но хотелось бы закрыть дескрипторы, вызвать деструкторы, обнулить кое-какие поля в структурах. Иными словами - привести систему в исходное состояние до выова подпрограммы. Такое возможно? Все переменные в процедурах и функциях PureBuilder строго локальные, никакие побочные эффекты не возможны, поэтому вызов процедуры/функции ничего не меняет в состоянии вызывающей процедуры/функции. Деструкторов в PureBuilder нет, так как концепция ООП заимствована из Oberon-07. Но если аварийная функция - уже по замыслу своего создателя опасная и низкоуровневая - взаимодействуя с ОС или через механизм указателей умудрилась что-то попортить, то у меня нет решения этой проблемы. Очевидно, что такие функции нужно создавать очень редко и предельно осторожно, и всегда иметь план Б, а лучше обходиться библиотечными, многократно проверенными. Механизм исключений - самый распрекрасный - вряд ли может помочь в такой ситуации. Вообще же необходимость включения механизма указателей в PureBuilder вызывает у меня массу отрицательных эмоций. Как сделать работу с указателями гарантированно безопасной, я не знаю. Но и как конструировать сложные структуры данных (всякие там красно-черные деревья), не имея указателей, я тоже не знаю. По-видимому, придется идти на неизбежный риск. Хотя самые популярные структуры данных нужно иметь в стандартной библиотеке. |
Автор: | Александр Шостак [ Понедельник, 07 Февраль, 2011 22:58 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Я имел в виду аналог ветки завершения у функции. Код, который идёт после второго // * * * * * //: Код: FUNCTION FileToMemEx ( CONST FilePath: STRING; (* On *) OUT MemBuffer: POINTER; OUT StrBuffer: STRING; OUT FileSize: INTEGER; BufferType: TBufferType ): BOOLEAN; VAR (* U *) Buffer: POINTER; hFile: INTEGER; FileSizeL: INTEGER; FileSizeH: INTEGER; BytesRead: INTEGER; BEGIN {!} ASSERT(MemBuffer = NIL); hFile := -1; StrBuffer := ''; Buffer := NIL; // * * * * * // RESULT := WinWrappers.FileOpen(FilePath, SysUtils.fmOpenRead OR SysUtils.fmShareDenyWrite, hFile); IF NOT RESULT THEN BEGIN Log.Write('FileSystem', 'OpenFile', 'Cannot open file "' + FilePath + '"'); END // .IF ELSE BEGIN RESULT := WinWrappers.GetFileSize(hFile, FileSizeL, FileSizeH); IF NOT RESULT THEN BEGIN Log.Write('FileSystem', 'GetFileSize', 'Cannot get size of file "' + FilePath + '"'); END; // .IF END; // .ELSE IF RESULT THEN BEGIN RESULT := FileSizeH = 0; IF NOT RESULT THEN BEGIN Log.Write ( 'FileSystem', 'LoadFile', 'Size of file "' + FilePath +'" exceeds 2 GB (=' + SysUtils.IntToStr(INT64(FileSizeH) * $FFFFFFFF + FileSizeL) + ')' ); END; // .IF END; // .IF IF RESULT AND (FileSizeL <> 0) THEN BEGIN IF BufferType = MEM_BUFFER THEN BEGIN GetMem(MemBuffer, FileSizeL); Buffer := MemBuffer; END // .IF ELSE BEGIN SetLength(StrBuffer, FileSizeL); Buffer := POINTER(StrBuffer); END; // .ELSE RESULT := WinWrappers.FileRead(hFile, Buffer^, FileSizeL); IF NOT RESULT THEN BEGIN Log.Write ( 'FileSystem', 'ReadFile', 'Error reading file "' + FilePath + '"' ); END // .IF END; // .IF // * * * * * // IF hFile <> -1 THEN BEGIN Windows.CloseHandle(hFile); END; // .IF IF RESULT THEN BEGIN FileSize := FileSizeL; END // .IF ELSE BEGIN IF BufferType = MEM_BUFFER THEN BEGIN FreeMem(MemBuffer); MemBuffer := NIL; END // .IF ELSE BEGIN StrBuffer := ''; END; // .ELSE END; // .ELSE END; // .FUNCTION FileToMemEx Допустим у вас язык со сборкой мусора. Но внешние ресурсы - это внешние ресурсы. Если деструкторов нет, а работа закончена на любом шаге, ресурсы нужно освободить. И тут как нельзя мешает ваш подход, когда всё кидает исключение. Функциям вдруг хочется выполняться на любом уровне до конца ) |
Автор: | Сергей Прохоренко [ Понедельник, 07 Февраль, 2011 23:53 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Александр Шостак писал(а): Допустим у вас язык со сборкой мусора. Но внешние ресурсы - это внешние ресурсы. Если деструкторов нет, а работа закончена на любом шаге, ресурсы нужно освободить. И тут как нельзя мешает ваш подход, когда всё кидает исключение. Функциям вдруг хочется выполняться на любом уровне до конца ) Не уверен, что правильно понял Ваш вопрос. Мне кажется, что Вы хотите, чтобы механизм исключений делал то, что должен делать сам программист. Исключения не могут возникать самопроизвольно. Они возникают при входе в функцию или выходе из функции - при нарушении "контракта". Они также возникают при попытке выполнить инструкцию, результат которой не гарантирован (ввод/вывод, размещение объектов в памяти). И это забота программиста - сделать так, чтобы код, освобождающий ресурсы, находился в вызывающей процедуре, а не в аварийной. Код аварийно завершаемой процедуры должен быть по-возможности минимального объема - максимум несколько строк. |
Автор: | Александр Шостак [ Вторник, 08 Февраль, 2011 01:03 ] |
Заголовок сообщения: | Re: Оцените механизм исключений в PureBuilder |
Я имел в виду, что если часто встречаются функции, которым нужна финализация работы, то единственный вариант для них - заводить булеву переменную и если она FALSE, то в конце функции бросать исключение. А такой подход уж очень близок к простому возврату true/false. |
Страница 2 из 2 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |