Здравствуйте, ambel-vlad, Вы писали:
E>С такой, что нам всё равно, что будет в случае исключения, которого не будет...
хочу заметить, что во всех тредах про исключения vs коды ошибок, Егор рассуждает о вакуумных конях, придумывает несуществующие проблемы которые с успехом сам и решает, и просто словоблудит =)
alex_public и еще кот-то, вообще приводили примеры, где исключения использовались для возврата значений.
просто мое наблюдение. сплошной фейспалм.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[57]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, Erop, Вы писали:
AV>>То что он выглядит не сильно приятно не отменяет того, что это он переписан в процедурном подходе. Это раз. И покажи не ужас, когда ошибку можно обработать на 4-5 уровней выше нежели ее обнаружение? И чтобы два раза не переписывать, то добавим, что верхняя фунция внутри себя вызывает не одну функцию, а три-пять. И те внутри себя тоже вызывают что-то. И при обработке ошибок на верхнем уровне хотелось бы знать что за ошибка произошла и в какой именно функции. А чтобы еще более весело стало, то функции, в которых возникают ошибки пишутся другими командами. Посему их изменить ты не можешь. А коды ошибок они используют одинаковые.
E>Во-первых, ты смешиваешь несколько разных, независимых обстоятельств. E>1) Что красивее E>2) Что дороже E>3) Что надёжнее
E>Собственно (1) я вообще не обсуждаю
Разве? "УГ код" — это не красивость разве*
E>Что касается (2) и (3), то использование всяких отмотчиков стеков RAII и т. д. в целом повышает надёжность кода на тему утечек. Правда совсем уж гарантий от них не даёт. Но какой-то уровень таки даёт, то есть в целом для среднего кода повышает его надёжность, повышает стоимость написания, но, возможно, снижает стоимость поддержки. E>Использование исклчений понижает надёжность кода, повышает стоимость поддержки, и, возможно и стоимость разработки.
Это еще требует доказательств.
E>Чтобы компенсировать негатив от внедрения исклбчений приходится вводить соглашения, вроде базовой гарантии при исключениях,
отказываясь от исключений, проблему ты оставляешь. Просто она лишь немного изменяет вид.
E>ещё раз повышает стоимость разработки,
повышает по сравнению с чем?
E>Я думаю, что ты со всем этим согласен, и весь вопрос в балансе этих вкладов.
Я из исключений не делал серебряной пули. За все надо платить. Но цена кодов возвратов в целом в большинстве случаев получается выше.
E>Ну там, готовы ли мы, что иногда будем падать?
Это не проблема исключений.
E>То есть какое падение в надёжность от перехода "RAII+исключения по исключительным случам" -> "исключения на каждый чих"
А не надо "исключение на каждый чих". С дуру сам знаешь что можно сломать.
E>Вот по моему опыту переноса больших программ, могу сказать, что течь базовой гарантии была третьим источником трудноотлаживаемых багов после багов/отличий коспиляторов и порядка инициализации и вообще работы статических переменных... E>Что как бы намекает
А при переносе программ с кодами ошибок таких багов не было?
Кстати, так что с примером кода?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Re[58]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, maxkar, Вы писали:
M>Так банально же... Для каждой строки предусловие "предыдущий фрагмент завершился успешно И некий предикат ИЛИ предыдущий фрагмент завершился с исключением А". И склеивается оно вполне нормально — "первый шаг завершился с ошибкой ИЛИ первый шаг завершился успешно И с предикатом И второй шаг завершился с ошибкой" и т.д.
M>А что мешает то? В catch мы попадаем, если есть ошибка. Задача catch — восстановить все варианты блока try{}catch{}. Если мы имеем некий формализм по описанию исключений, мы знаем, в какой строке выше какие исключения могут происходить. В чем проблема то? Если ошибки нет, мы в catch не попадем. Если ошибку не обработали, то мы вообще в весь остаток функции не попадем.
Проблема в структуре получающихся предикатов.
Их либо вообще не получается написать, либо получается, что всё зависит от всего.
Ну то есть в НОРМАЛЬНОЙ программе кроме того, что у нас будет функция, read_profile, которая спрячем внутри себя подробноти как там и откуда итается профиль, за одно и предусловие этой функции свернётся в "профиль доступен", А в программе которая написана, так что у нас стек вызовов глубиной а пять функций. шириной в 10 и наружу торчат 100500 исключений, то там получится предусловие вида " на таком-то смещее в таком-то файле стоиит цифра, а не буква" и так 100500 раз...
Собственно полезная логика в этом шуме просто утонет бесследно и всё. А так пролем никаких нет
Кроме той проблемы, что нет и смысла.
В принципе ждя многих лапшеобразных программ тоже можно наделать всяких хитрых преобразований и допущений и таки написать какие-то пред/пост-условия, только их структура тоже будет плохой и мало поможет в написании и подержке программы...
Это и говорит нам о том, что подход не работает...
M>Кстати, а вы допускаете return в середине функции? Без него некоторые программы читаются гораздо хуже (глубокая вложенность из if'ов читается тяжеловато). А с ними возникают все те же проблемы — как объединять все предикаты из разных return на выходе из программы (например, чтобы проверить очистку ресурсов).
Ну без фанатизма если, то допускаю...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[60]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, maxkar, Вы писали:
M>А зачем так делать? Откуда там произвольные исключения? Можно ведь взять checked exceptions, например, и ограничить их спектр. Так что проблем не будет. То, что c++ не использует checked exception, это его проблемы.
Ну мы же обсуждаем РЕАЛЬНЫЕ практики, а не гипотетические?..
И с самого начала эта тема была в С++/С, так что плюсовые к тому же.
В той же Яве всё-таки есть GC, что очень упрощает жизнь программам с исключениями.
Гарантии безопасности проще намного выглядят и обеспечить их тоже проще...
M>(а в большинстве случаев контракты вообще отсутствуют, так как программисты не любят писать документацию).
Так я про то и пишу, что рассчитывать на повсеместное соблюдение базовой гарантии в большой С++-программе несколько слишком оптимистически-самонадеянно...
Собственно это главный недостаток исключений -- понижение надёжности С++ программ непредсказуемым образом. Второй недостаток -- более запутанная семантика кода, в принципе, лечится правильной архитектурой, только правильносто архитектуры так же будет обеспечиваться, как и бащовая гарантия, то есть с дырами.
Но это просто значит, что в программе будут дорогие в поддержке мутные места, а не то, что программа время от времени будет демонстрировать UB в полный рост...
M>Забудьте вы про доказуемость. Дейкстра свой труд писал давным давно, тогда многое было по-другому. Его утверждения про доказуемость применимы в первую очередь к неполиморфным участкам кода. Как только появляется полиморфмизм, все доказательства и контракты усложняются. Если полиморфизм открытый (пользователь может создать еще наследников классов или передать что-то свое в библиотеку), ситуация еще более усложняется.
Конечно усложняется, но сила подхода процедурного программирования не в том, что что-то можно доказать, а в том, что оно даёт нам хороший способ адекватно описать сложность программы и контролировать код.
M>И еще. Я очень плохо представляю, как можно доказывать базовые гарантии обработки ошибок в реальной жизни. Проблема очень простая. Пусть что-то у нас сломалось, мы решили очистить ресурсы и вернуть код ошибки.
Не очень понятно, что такое "какая-нибудь ошибка"?..
Если это ожидаемое поведение, ну там грузили что-то грузили и так и не загрузили, то это как бы просто постусловие просто функции. Обычными методами всё разрулится. Если в языке есть GC, то просто 0 можно из функции вернуть, а дальше пусть GC парится. Если нет, то разрушим, так же, обычно. Или достроим, а потом разрушим. В общем не понятно чем эта ситуация отличается от разных других ситуаций...
M>Вопрос: как доказать, что мы не поймаем переполнение стека в процессе очистки уже выделенных ресурсов?
Обычно проблему переполнения стека считают фатальной. Так же как и другие версии нехватки памяти... В целом есть много способов с этим бороться, но самый хороший -- не иметь риска, что она вообще возниктнет.
M>Кстати, что там будет с переполнением стека в C++? На той же java я его могу поймать и обработать. Да, это нужно далеко не везде, но все же может быть нужно. Например, я запускаю какой-нибудь рекурсивный поисковой алгоритм в отдельном потоке. Если алгоритм прошел, хорошо. Если не прошел (не хватило стека), я запускаю другой алгоритм (более медленный/с худшими результатами) и получаю результат от него. Можно делать подобное в процедурном стиле? И как вы будете в этом случае доказывать, что "стека на очистку данных хватит даже если где-то в середине вычисления стека для того шага не хватило"?
Я бы на С++ намеренно переполнять стек не стал бы. Я бы ловил таки момент, когда до исчерпания стека останется ещё достаточно долго, скажем половина зареервированной памяти, и обламывался уже тогда контролируемым способом, или просто отказался бы вообще от рекурсивного алгоритма, всмысле переписал бы его на итерационный...
Можно пример алгоритма, о котором речь, кстати?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[56]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, ambel-vlad, Вы писали:
AV>И покажи не ужас, когда ошибку можно обработать на 4-5 уровней выше нежели ее обнаружение? И чтобы два раза не переписывать, то добавим, что верхняя фунция внутри себя вызывает не одну функцию, а три-пять. И те внутри себя тоже вызывают что-то. И при обработке ошибок на верхнем уровне хотелось бы знать что за ошибка произошла и в какой именно функции.
Ну, как бы, в нормальных программах принято скрывать подробности реализации от клиентского кода.
То есть если тебе функция fopen вернёт что-то вроде ("список в таком-то блоке исчерпан") вместо "нет файла" или там "нет доступа"...
То есть тут во джассер про еррор-проне код писал там и т. п.
Так тут получилось смешение двух РАЗНЫХ подходов и смешение аргументаций за тот и за другой...
Идея про еррор-проне состоит в том, что надо паисать программы так, что бы писать правильные программы было удобнее, чем неправильные.
И один из подходов на эту тему состоит в том, что бы программа максимально бысро "выламывалась", а не продолжала делать что-то не понятное, пока не упрётся в совсем какое-то непреодолимое противоречие, вроде перехода по невалидному адресу и т. п.
И в рамках этого подхода, в случае если исклчения -- это способ "выламываться", то их хорошо кидать везде, где что-то не то замечено.
А есть другой подход, типа у нас всё ходит, мы всё написали, а если что-то не так, кидаем исключение и надеемся, что всё срастётся где-то выше по стеку.
То есть, если в случае кодов возврата, мы явно везде должны продумать что будет происходить, если случится такой облом или сякой.
А в случае исклбчений можем подумать, а можем и не подумать, в целом-то наши раздумия никаких следов в кое не отсавляют
AV>А чтобы еще более весело стало, то функции, в которых возникают ошибки пишутся другими командами. Посему их изменить ты не можешь. А коды ошибок они используют одинаковые.
Для сравнения предлагаю рассмотреть случай, когда функции пишутся разными командами и с разными подходами, но с исключениями
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ambel-vlad, Вы писали:
AV>Зато нам не все равно что будет в случае ошибки. Проблем никуда не делась.
Тут есть некоторая терминологическая путанница.
"ошибка" -- это что? То, что входит в ТЗ, грубо говоря, или то, чего мы не ждём и обрабатывать не планируем.
Если первое, то это надо покрывать тестами, поддерживать в коде и т. д.
Если второе, то нам пофигу что будет, когда случится то, чего быть не должно...
Вернее не пофигу, а ообычно надо минимализировать вероятность наступения того, чего быть не должно. а не улучшать поведение программы в этом маловероятном сценарии
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[57]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, Erop, Вы писали:
AV>>И покажи не ужас, когда ошибку можно обработать на 4-5 уровней выше нежели ее обнаружение? И чтобы два раза не переписывать, то добавим, что верхняя фунция внутри себя вызывает не одну функцию, а три-пять. И те внутри себя тоже вызывают что-то. И при обработке ошибок на верхнем уровне хотелось бы знать что за ошибка произошла и в какой именно функции.
E>Ну, как бы, в нормальных программах принято скрывать подробности реализации от клиентского кода.
вот у тебя обломилось получение байти из сокета. Как ты собираешься это обрабатывать в функции чтения данных из сокета?
E>То есть тут во джассер про еррор-проне код писал там и т. п.
Ты не на других переводи стрелки, а покажи пример кода.
E>И один из подходов на эту тему состоит в том, что бы программа максимально бысро "выламывалась", а не продолжала делать что-то не понятное, пока не упрётся в совсем какое-то непреодолимое противоречие, вроде перехода по невалидному адресу и т. п.
Забытая проверка кода ошибки скорее приведет к второму подходу. Когда остается только гадать что же в действительности произошло.
E>А есть другой подход, типа у нас всё ходит, мы всё написали, а если что-то не так, кидаем исключение и надеемся, что всё срастётся где-то выше по стеку.
Исключение — это не только их бросание, но и обработка. Иначе зачем их бросать.
E>То есть, если в случае кодов возврата, мы явно везде должны продумать что будет происходить, если случится такой облом или сякой.
Слишком много приходится думать. И поэтому рано или поздно забудешь подумать.
E>А в случае исклбчений можем подумать, а можем и не подумать, в целом-то наши раздумия никаких следов в кое не отсавляют
Можем не подумать. Только это, как правило, быстрее обнаружится.
AV>>А чтобы еще более весело стало, то функции, в которых возникают ошибки пишутся другими командами. Посему их изменить ты не можешь. А коды ошибок они используют одинаковые.
E>Для сравнения предлагаю рассмотреть случай, когда функции пишутся разными командами и с разными подходами, но с исключениями
Ты сначала приведи свой код с кодами ошибок. Кстати, про разные подходы ты добавил от себя. Не хочешь примерить это уточнение к коду, который ты приведешь?
Здравствуйте, Erop, Вы писали:
AV>>Зато нам не все равно что будет в случае ошибки. Проблем никуда не делась.
E>Тут есть некоторая терминологическая путанница. E>"ошибка" -- это что? То, что входит в ТЗ, грубо говоря, или то, чего мы не ждём и обрабатывать не планируем.
То что ты в месте возникновения не знаешь как обработать. А обработать можешь в другом месте.
В случае исключений ты требуешь соблюдения инварианта, а в случае кодов ошибок это святой дух обеспечивает?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Re[58]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, ambel-vlad, Вы писали:
AV>Разве? "УГ код" — это не красивость разве*
Это дороговизна поддержки. О вкусах вообще спорить мало смысла
E>>Использование исклчений понижает надёжность кода, повышает стоимость поддержки, и, возможно и стоимость разработки.
AV>Это еще требует доказательств.
А что из тёх вызывает сомнения? Если в среднюю прогу на С вклячить исключения, случиться клиьма 146%.
Так что для обеспечения просто работоспособности, а не то что бы надёжности, надо таки проводить какие-то ДОПОЛНТЕЛЬНЫЕ мероприятия, в которых ещё и ошибиться можно...
AV>отказываясь от исключений, проблему ты оставляешь. Просто она лишь немного изменяет вид.
Какую конкретно проблему?..
AV>Я из исключений не делал серебряной пули. За все надо платить. Но цена кодов возвратов в целом в большинстве случаев получается выше.
Ну вот мы и пришли к тому же, к сравнению стоимостей тех или иных подходов...
AV>А не надо "исключение на каждый чих". С дуру сам знаешь что можно сломать.
Ну так это же и обсужается, можно ли исключения кидать часто, или таки если мы уж кинули исклбчения, то это примерно как провал assert'а по степени ожидаеммости...
AV>А при переносе программ с кодами ошибок таких багов не было?
Ну ошибки есть всегда. Но обычно есть ТЗ, тесты, логи...
А с исключениями обычно ничего нет, все надеются, что всё будет "само"...
В принципе я их понимаю, что если на "само" не рассчитывать то с исключениями выходят СЛОЖНЕЕ, чем с условными кодами возврата...
AV>Кстати, так что с примером кода?
С примером кода чего конкртено?
Я тут в этих двух темах приводил уже кучу примеров разного кода...
Мне тут всё собщают, что типа это всё кони в вакууме...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[59]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, Erop, Вы писали:
AV>>Разве? "УГ код" — это не красивость разве* E>Это дороговизна поддержки. О вкусах вообще спорить мало смысла
А там не был код для работы человека с ним. Там код был для других целей.
E>>>Использование исклчений понижает надёжность кода, повышает стоимость поддержки, и, возможно и стоимость разработки.
AV>>Это еще требует доказательств. E>А что из тёх вызывает сомнения?
Все три.
E>Если в среднюю прогу на С вклячить исключения, случиться клиьма 146%.
Если их только выбрасывать, то так и будет.
E>Так что для обеспечения просто работоспособности, а не то что бы надёжности, надо таки проводить какие-то ДОПОЛНТЕЛЬНЫЕ мероприятия, в которых ещё и ошибиться можно...
Какие дополнительные мероприятие необходимо проводить?
AV>>отказываясь от исключений, проблему ты оставляешь. Просто она лишь немного изменяет вид.
E>Какую конкретно проблему?..
Сохранения инварианта
AV>>Я из исключений не делал серебряной пули. За все надо платить. Но цена кодов возвратов в целом в большинстве случаев получается выше.
E>Ну вот мы и пришли к тому же, к сравнению стоимостей тех или иных подходов...
От этого и не уходили.
AV>>А не надо "исключение на каждый чих". С дуру сам знаешь что можно сломать. E>Ну так это же и обсужается, можно ли исключения кидать часто,
Что есть "чих"?
E>или таки если мы уж кинули исклбчения, то это примерно как провал assert'а по степени ожидаеммости...
Облом с чтением байта их сокета такой случай?
AV>>А при переносе программ с кодами ошибок таких багов не было? E>Ну ошибки есть всегда. Но обычно есть ТЗ, тесты, логи... E>А с исключениями обычно ничего нет, все надеются, что всё будет "само"...
Чего-чего? Ты беленой объелся? Если ты в качестве плохого кода с исключениями приводишь какое-то откровенное дерьмо, то я такого же дерься навидался и с кодами возвратов. Развесистый макаронокод с несколькими десятками ифов в одной функции. Причем, как и ожидалось, кучу кодов ошибок забывали проверить. А потом когда возникала ошибка, то ломали голову. Потому что не могли найти ошибку.
AV>>Кстати, так что с примером кода?
E>С примером кода чего конкртено?
Здравствуйте, Erop, Вы писали:
T>>Принципиальной разницы нет, и то и другое это исключения.
E>Тебе кажется, что возможность не разматывать стек непринципиальна?
Это детали реализации. Главное что твой вариант это тоже исключения и код обработки находит в одном месте.
The animals went in two by two, hurrah, hurrah...
Re[58]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, ambel-vlad, Вы писали:
AV>вот у тебя обломилось получение байти из сокета. Как ты собираешься это обрабатывать в функции чтения данных из сокета?
Вернёшь ошибку, тот, кто позвал -- разберётся...
Если так удобнее вызывающей стороне, то можно представить вызывающей сотроне версию функции read_byte, которая падает при обломе по assert там или по имключению... не суть.
AV>Забытая проверка кода ошибки скорее приведет к второму подходу. Когда остается только гадать что же в действительности произошло.
Так на это есть тестирование и меры, по обеспечению его полноты...
AV>Исключение — это не только их бросание, но и обработка. Иначе зачем их бросать.
Ну ясен пень обработка где-то какая-то будет. Вопрос лишь в том удачная ли
AV>Слишком много приходится думать. И поэтому рано или поздно забудешь подумать.
Ну так ведь и при программировании всё время думать приходится...
То, что ты где-то подумать не забыл, можно легко проверить...
AV>Можем не подумать. Только это, как правило, быстрее обнаружится.
Почему? Пиши aasert'ы так, что бы программа ыстро выламывалась и всё обнаружится быстро что так что этак...
AV>Ты сначала приведи свой код с кодами ошибок. Кстати, про разные подходы ты добавил от себя. Не хочешь примерить это уточнение к коду, который ты приведешь?
Ну это любой обычный код так выглядит. Скажем никогда не видел std::cout и сервисы из stdio в одной программе?
Я уже приводил примеры кода. Но их тут обозвали абстрактными...
Ну я так понимаю, что всё программистское сообщество сломало себе зубы на задачке написать типа парсер файла профайла без использования исключений и при этом хорошо и понятно?
Ну типа будет какой-то класс CConfigParser, на вход которого (например в конструктор ) будут передавать текст конфигурационника, или какой-то аналог, скажем открытый поток.
CConfigParser будет иметь какой-то интерфейс, типа там считать следующую секцию, проитерировать ключи в секции и т. д.
По концу файла, например, будем просто считать, что строчка закончилась, или будем как-то специально обрабатывать -- не суть. Мне кажется, что парсеру должно быть пофиг, почему текст закончился. Максимум что волнует -- аварийно или нет.
Ну потом будет какой-то CProfileReader, который будет получать на вход источник конфига, создаст
CConfigParser, вычитает нужные поля, как-то обработает их отсутсвие, и выставит флажки о степени готовности + сформирует информацию о недоступности конфига или о наличии ошибок в формате файла и степени их тяжести.
Потом ещё более внешний код, уже уровня прогрмаммы, будет там как-то решать что делать с тем где искать конфиг, и что делать если он читается или нет. Может быть там где-то, наконец бросят исклчение с текстом, чт типа фатально не тот формат такого-то файла. А может сначал спросят, не перехаписать ли дефолтными значениями? И только если пользователь скажет, что типа нафиг, тогда отгрузку нанёт...
Что конкртено из этого ты хотел бы, что бы я написал?..
Ну, в смысле, что конкретно ты сам не знаешь, как обычно пишут?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ambel-vlad, Вы писали:
AV>В случае исключений ты требуешь соблюдения инварианта, а в случае кодов ошибок это святой дух обеспечивает?
Ну это же просто код будет, без вылета любоо исключения из любого места? То есть надо просто к моменту return что бы всё было корректно...
Ты приведи пример функции, где это трудно обеспечить, может я просто не понимаю о чём речь?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Tanker, Вы писали:
E>>Тебе кажется, что возможность не разматывать стек непринципиальна?
T>Это детали реализации. Главное что твой вариант это тоже исключения и код обработки находит в одном месте.
Ха, так в этих-то деталях весь дьявол-то и сидит
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
AV>>В случае исключений ты требуешь соблюдения инварианта, а в случае кодов ошибок это святой дух обеспечивает?
E>Ну это же просто код будет, без вылета любоо исключения из любого места?
Да.
E>То есть надо просто к моменту return что бы всё было корректно...
да, чтобы к моменту return все было корректно. Как ты это собираешься обеспечивать в случае кодов ошибок?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Re[59]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, Erop, Вы писали:
AV>>вот у тебя обломилось получение байти из сокета. Как ты собираешься это обрабатывать в функции чтения данных из сокета?
E>Вернёшь ошибку, тот, кто позвал -- разберётся...
А тот кто позвал тоже не знает что делать с этой ошибкой. Кидаем код ошибки еще выше?
AV>>Забытая проверка кода ошибки скорее приведет к второму подходу. Когда остается только гадать что же в действительности произошло.
E>Так на это есть тестирование и меры, по обеспечению его полноты...
Простой пример. Была функция. Не тобой написанная. Но ты ее юзаешь. Написал тесты. Все хорошо. Потом пришла новая версия этой функции. С новым кодом. О котором ты не знал или забыл. Как твои старые тесты это отловят?
AV>>Исключение — это не только их бросание, но и обработка. Иначе зачем их бросать. E>Ну ясен пень обработка где-то какая-то будет. Вопрос лишь в том удачная ли
А почему она будет удачная в случае кодов ошибок и будет неудачная в случае исключений? Может дело не в инструменте, а в голове?
AV>>Слишком много приходится думать. И поэтому рано или поздно забудешь подумать. E>Ну так ведь и при программировании всё время думать приходится...
Может стоит думать над полезной функциональностью, а не как бы не пропустить какую-либо ошибку. А то если ее забыть, то где и когда она всплывет неизвестно.
E>То, что ты где-то подумать не забыл, можно легко проверить...
Каким образом?
AV>>Можем не подумать. Только это, как правило, быстрее обнаружится. E>Почему? Пиши aasert'ы так, что бы программа ыстро выламывалась и всё обнаружится быстро что так что этак...
И толку в таком ассерте в точке обнаружения проблемы? Там мы не знаем надо ломаться или нет. И даже на один вызов выше мы не знаем можем не знать надо ломаться или нет.
AV>>Ты сначала приведи свой код с кодами ошибок. Кстати, про разные подходы ты добавил от себя. Не хочешь примерить это уточнение к коду, который ты приведешь?
E>Ну это любой обычный код так выглядит. Скажем никогда не видел std::cout и сервисы из stdio в одной программе?
Видел. И не такое видел. И что?
E>Я уже приводил примеры кода. Но их тут обозвали абстрактными...
Я просил более чем конкретный код. И пишется он не так уж и долго. Но на протяжении нескольких сообщений это вызывает затруднения у тебя. Или какая-то другая причина не дает тебе это сделать?
Здравствуйте, maxkar, Вы писали:
M>Так вы же сами просили "ошибки подробно" описывать. И говорили, что на кодах ошибок это проще, чем на исключениях . И я в предыдущем сообщении показывал, как это будет "по-умолчанию" с тремя уровнями исключений (без дополнительной обертки в readFieldGroup и т.п.). Завернуть все в unchecked и отлавливать на верхнем уровне тоже можно, но во вполне конкретных случаях и понимая, зачем и что с этим делать. Я за проработку обработки ошибок на ранних стадиях. Поэтому переоборачивание ошибок на границах слоев абстрации для меня — действие по умолчанию. Все исключения методов должны быть только в терминах интерфейса. Поэтому абстрактный ProfileService не может принципиально выбрасывать IOException. ProfileException — может. ProfileNotFound — может. А вот IOException — никогда.
Нет, подробно описывать ошибки предложил как раз jazzer. Я же предпочитаю стараться строить архитектуру так, что бы вызовы сводились возвращению true/false, т.к. в большинстве случаев пользователю не нужны никакие технические подробности. Они нужны скорее разработчикам для отлова ошибок, но это полезнее реализовывать совсем другими методами (из области АОП), а не пронизывать ими основную логику.
Да, а та моя мысль была немного в другом. Что если уж у нас почему то и стоит задача возвращать подробные ошибки и это надо делать через исключения, то корректно это можно сделать только как раз по вашей схеме. Т.е. я полностью согласен с вашим подходом реализации работы с исключениями, если уж их использовать в таких местах. Однако при такой схеме объём кода становится уже явно не меньше того самого "проброса кодов возврата".
M>Не будет. jazzer правильный пример привел. Для опциональных полей будут опциональные обертки (которые при этом еще по контракту и состояние потока оставляют во вполне определенном состоянии, а не "где сломалось"). Там же отсутствие поля — вполне ожидаемая ситуация. В крайнем случае, будут возвращать null/not null или какой-нибудь простенький Option с методом hasValue(). А вот IOException будет пробрасываться дальше. Как вы на кодах ошибок будете в данной ситуации действовать? Причем вам теперь нужно проверять, что именно там сломалось: M>
M>И если вдруг поломок будет более одной, все будет еще сложнее (несколько проверок после каждой функции). Если же вы каким-то другим способом предложите переписать код "с использованием кодов ошибок", я подобное же преобразование сделаю и для java, заменив только коды ошибок исключениями.
Это вы уже куда-то не туда пошли. Всё гораздо проще. Если у нас стоит условие, что какие-то поломки в конфиге должны прерывать исполнение программы, то это одна схема. И собственно тогда никто не против применения исключений тут. Только тогда уже совсем не по вашей схеме с обработкой на каждом уровне, а как раз с одним обработчиком на самом верху. Если же программа должна в любом случае продолжить исполнение, то становится уже не важно по какой причине нам подставлять дефолтное значение в поле, из-за того что его не было в конфиге или из-за того что некорректно записано или ещё из-за чего.
M>"Одно объявление классов ... с их полями и конструкторами" — это не свойство исключений. Это свойство поставленной вами задачи "выводить ошибки подробно". И большое количество классов следует из того, что классов ошибок на самом деле много и их нужно как-то описывать. Поэтому не важно, как именно вы это будете делать — исключениями, кодами ошибок или монадой со строго типизированными ошибками. Если убрать это требование, у меня будут исключения с одним/двумя конструкторами (делегирующим родителю) и вообще без полей, например. Т.е. проблема к исключениям отношения не имеет. Да, в Java record и discriminated union очень многословно руками записывают. Мне это надоело и при следующей необходимости discriminated union я их себе сделаю (на xtext + кодогенерация). В данном случае исключения — частный случай discriminated union (открытый или закрытый в зависимости от ситуации). Но, повторюсь, это не проблема исключений, это проблема описания обычных типов данных. Какой-нибудь struct для тех же случаев (вместе с инициализацией) будет ничуть не лучше (а то и хуже). А так как struct вернуть из метода еще и не так просто, то на "кодах возврата" подробная информация обычно как раз не делается. Банально не удобно и получается очень много кода.
Отдельно замечу что примеры из Java не совсем корректны в теме о пользе C++ исключений, т.к. в Java у исключений есть одно небольшое преимущество. А именно, там весь низкоуровневый api изначально кидает исключения. В то время как в случае C++ на низшем уровне мы обычно имеем дело с вызовами OS api или чем-то подобным, но в любом случае работающем через коды возврата. Т.е. возвращаясь к теме, если в Java код на самом низшем уровне будет выглядеть как "DoSomething();" и это уже будет кидать исключения (а для кодов возврата надо ещё постараться), то в C++ и коды возврата и исключения выглядят на этом уровне наравне: "if(!DoSomething()) return false;" или "if(!DoSomething()) throw MyException();".
А вообще давайте вернёмся к самой основе дискуссии, что бы разобраться есть ли у нас базовые разногласия. А то вы вступили в неё на уровне обсуждения мелких деталей.
И так на мой взгляд ошибки возникающие в приложениях лучше всего обрабатывать с помощью исключений. При условие что под ошибкой подразумевается ситуация требующая прерывания исполнения приложения (ну или потока). Преимущества исключений тут в автоматической глубокой раскрутке стека. Причём в C++ тут преимуществ даже больше чем у Java за счёт RAII.
Однако многие программисты расширяют значение термина "ошибка" до чего-то типа "возврат неудачи функции", которое совершенно не обязательно должно прерывать нормальное исполнение программы, а всего лишь направляет по другому сценарию. И в такой ситуации у исключений уже нет никаких особых преимуществ автоматизма, т.к. по нормальному обработка (пускай это и переупаковка исключения всего лишь) такой ошибки происходит на локальном уровне (в отличие от настоящих ошибок, обработчик которых скорее всего один глобальный). Соответственно применяя исключения в такой ситуации мы выполняем лишнюю работу (классы исключений, сам код больше и т.п.) не получая от этого никаких реальных преимуществ.
M>Да, еще одна проблема "на кодах возврата". Исключения, все-таки, представляют собой открытое легко расширяемое множество с некоторыми концепциями именования. Это с большой долей вероятносит гарантирует, что "двух одинаковых" исключений в никаких библиотеках не будет (именование пакетов вроде com.acme.product...). А вот набор кодов ошибок ограничен. Так что вполне вероятно, что две библиотеки будут иметь пересекающиеся диапазоны кодово ошибок с различной семантикой? Что вы будете делать в этом случае? Делать кучу оберток вокруг одной из библиотек, переводя ее коды в коды своего приложения? Будете вручную на каждый вызов переделывать кучи ошибок (почти предыдущий вариант, только обработка по месту вызова)? Или ничего не будете делать и предоставите пользователю возможность угадывать, что же на самом деле там сломалось с кодом ошибки 0x3211? Даже "исключения по-умолчанию" (без корректного оборачивания на нужных уровнях) придут с правильным описанием ошибки (правда, слишком низкоуровневым) и гадать нужно будет не так много.
Эээ ну это то как раз вообще не проблема. Причём ни при кодах возврата, ни при вашей схеме работы с исключениями. У нас же всё обрабатывается локально (на предыдущем уровне, а не где-то далеко назад по стеку) и соответственно код всегда знает контекст ошибки.
Re[56]: Слушайте, люди добрые, а правда, есть мат аппарат анализа кода с иключен
Здравствуйте, ambel-vlad, Вы писали:
AV>То что он выглядит не сильно приятно не отменяет того, что это он переписан в процедурном подходе. Это раз. И покажи не ужас, когда ошибку можно обработать на 4-5 уровней выше нежели ее обнаружение? И чтобы два раза не переписывать, то добавим, что верхняя фунция внутри себя вызывает не одну функцию, а три-пять. И те внутри себя тоже вызывают что-то. И при обработке ошибок на верхнем уровне хотелось бы знать что за ошибка произошла и в какой именно функции. А чтобы еще более весело стало, то функции, в которых возникают ошибки пишутся другими командами. Посему их изменить ты не можешь. А коды ошибок они используют одинаковые.
Это же уже обсуждалось прямо в этой теме. Вы предлагаете Егору написать говнокод на кодах возврата и показать на нём что аналогичный говнокод на исключениях будет проще. Очень сомнительная идея.
Здравствуйте, ambel-vlad, Вы писали:
AV>Кто тебе сказал что не можем? Еще как можем. Исключения можно вкладывать друг в друга. А то при помощи кодов ошибок сообщить это гораздо сложнее.
Естественно можно вкладывать но тогда соответствующие try/catch/throw расползаются по стеку вызова ничуть не слабее тех самых пробросов кодов возврата. И соответственно такой код начинает требовать больших (не забываем про классы исключений и т.п.) усилий, чем код с кодами возврата.
P.S. Это всё уже обсуждалось прямо в этой темке — читайте что ли в начале все её подветки, а то лень повторяться. )
Здравствуйте, ambel-vlad, Вы писали:
AV>да, чтобы к моменту return все было корректно. Как ты это собираешься обеспечивать в случае кодов ошибок?
Ну так же, как и остальные постусловия. ВОт как ты, например, собираешься обеспечивать отсортированность массива к концу функции sort?
Программирование там, тестирование модульное и функциональное и т. д...
Кодирование, короче, типа
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском