LINUX.ORG.RU

Каскады iferr: как живете с ними?

 ,


2

3

Не секрет, что практически все функции в Golang возвращают ошибки. И тут два пути: или игнорировать или обрабатывать в iferr. Игнорировать почти никогда не получается, так что выбор невелик и код превращается в

val, err := SomeFunc()
if err != nil {
..do some..
}
. Да, это правильно, но это ж на каждый чих проверка получается. Нельзя ли сделать для этого условный defer или как-то иначе скрыть явную обработку ошибок? Может, кодогенерация поможет или еще что? Как вы пишете максимально чистый и компактный код?

Ответ на: комментарий от Lrrr

может кто-нибудь такое уже придумал

плохая идея. Ошибка тут в SomeFunc1 или SomeFunc2? придется писать код, выясняющий где оно случилось или иметь разные типы ошибок и разные ветви catch.

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

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

Ага, копипаста очень наглядна)) И мозг включать не надо, написал в десяти местах одно и тоже и все наглядно))

PRN
()
Ответ на: комментарий от PRN

Ага, копипаста очень наглядна))

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

вы знаете хоть, что делается при входе в блок try и выходе по исключению в один из блоков catch? какой там код будет дополнительный?

alysnix ★★★
()
Ответ на: комментарий от alysnix

вы знаете хоть, что делается при входе в блок try и выходе по исключению в один из блоков catch? какой там код будет дополнительный?

LOL. Сейчас лоровские школьники меня научат плюсам)) Ну давай, рассказывай. Тему кейворда noexcept раскрыть не забудь. XD

PRN
()
Ответ на: комментарий от PRN

как оформляется код операторов try… catch, уважаемый. и сравните это с обработкой ошибок на месте, с накладными расходами равными нулю.

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

обработкой ошибок на месте, с накладными расходами равными нулю.

Если что этот код имеет не «нулевые расходы»

    if err := datastore.Get(c, key, record); err != nil {
        return &appError{err, "Record not found", 404}
    }

Пока err не известно конвеер продвинуться не может, но в современных процессорах это нивелируется спекулятивными вычислениями. И вполне возможна ситуация что простой вызов

datastore.Get(c, key, record)

может работать быстрее, пока исключение не кинет, но и тут есть нюансы))

то есть генерить исключение в функции и немедля его обрабатывать в вызывающей функции - это ахтунг.

Тебя кто-то заставляет так писать? К чему ты это написал? Сам придумал говнокод, сам его опроверг. Так ты сам с собой поговорить можешь))

PRN
()
Последнее исправление: PRN (всего исправлений: 1)
Ответ на: комментарий от PRN

Пока err не известно конвеер продвинуться не может, но в современных процессорах это нивелируется спекулятивными вычислениями. И вполне возможна ситуация что простой вызов

во коней пришпорил. куда тебя понесло, какие еще конвейеры и спекулятивные вычисления. просто посмотри уже как генерится код throw. вне зависимости от языка.

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

то есть в оформлении оператора try-catch происходят такие вещи - код толкания текущего хадлера обработки ошибки в стек или список(зависит от реализации), код выталкивания хандлера(в конце блока try), код самих хандлеров, код сравнения сигнатуры или еще чего ошибки в сигнатурой хандлера.

то есть кот такая вот куча мала делается только для того чтобы какой-то шнырь типа «избавился от копипасты».

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

плохая идея. Ошибка тут в SomeFunc1 или SomeFunc2? придется писать код, выясняющий где оно случилось или иметь разные типы ошибок и разные ветви catch.

а чем iferr решает проблему разных типов ошибок? Правильно, ничем.

В golang мы стираем тип у err и вообще не особо паримся из-за аллокаций в куче - ну так и в C++ никто не запрещает наследовать исключения от std::exception и потом ловить этот базовый класс.

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

нет конечно. Наоборот, за кучу ифов в коде ты платишь всегда, вне зависимости от того, возникают у тебя ошибки или нет. У исключений другой профиль. В C++ они очень дорогие, да, - но во первых нужна ли тебе производительность в случае ошибки, во-вторых это проблема не исключений как подхода, а занимающегося какой-то фигней комитета по стандартизации языка.

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

Lrrr ★★★★★
()
Последнее исправление: Lrrr (всего исправлений: 1)
Ответ на: комментарий от alysnix

то есть в оформлении оператора try-catch происходят такие вещи - код толкания текущего хадлера обработки ошибки в стек или список(зависит от реализации)

Ого как сложно в список «указатель» то запихнуть. Ну все перехожу на счеты, там и просто и наглядно XDD

PRN
()