LINUX.ORG.RU

Success Exception? WTF?

 , ,


0

0

Здравствуйте мои дорогие, великие программисты, бакалавры и прочие ЛОРовцы включая умнейших анонимусов!

А вот что если я вам скажу следующее:

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

И вот есть код, в котором, где-то в дебрях, при определённых условиях требуется:

а) вывалить сообщение и сделать exit(0);

б) сделать exit(0) без каких либо сообщений вообще.

Приведу простой пример: программа выполняется по крону, и нужно, в случае штатного завершения, не засирать логи кронтаба и не слать емейлы тому, от чьего имени эта программа по крону запускается. Вот тут и пригождается кейс «б» — код завершения есть, а сообщения нет.

К чему это я? А к тому, что можно же использовать для этого исключения. А что? Исключение бросается в исключительной ситуации. Но исключительная ситуация не обязательно ошибка!

И теперь у меня есть «SuccessException(message)» и, конечно, «JustSuccessExit extends SuccessException»

А что вы думаете по этому поводу?

UPD: ПОЖАЛУЙСТА, ПРЕЖДЕ ЧЕМ НАПИСАТЬ СООБЩЕНИЕ — ПРОЧТИТЕ ВЕСЬ ТРЕД!!! СКОРЕЕ ВСЕГО ВАШ ВОПРОС ИЛИ ВАША ПРЕТЕНЗИЯ УЖЕ ОБСУЖДАЛАСЬ!

★★★★★

Последнее исправление: deep-purple (всего исправлений: 2)
Ответ на: комментарий от ma1uta

Каким образом гарантируется

Тем что в нудном месте написано catch

там что-либо изменить приводит к боли и страданию

Тебе какое-то говно показывали.

Человеческий фактор

Вот ты что-то поменял, дополнил. Тесты на что?

тут дело не в безмозглости

Именно в ней.

А ещё в святой вере в хрен пойми когда и кем сказанное, пустившее метастазы повсюду.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от PRN

А если не удалось то исключительная?

Очень странно спрашивать мнение форумчан, а потом поливать их говоном

Очень странно? Это щас народ прибежал говном лить. А не я тут всех поливаю. Я лишь на поливание в свою сторону отвечаю. Причем с аргументами.

deep-purple ★★★★★
() автор топика
Последнее исправление: deep-purple (всего исправлений: 1)

ты (и другие любители исключений) используешь исключения как goto. это отвечает на твой вопрос?

anonymous
()
Ответ на: комментарий от deep-purple

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

Но если у тебя защита от повторных запусков в кроне, то зачем это в код тащить? Есть простой flock предназначенных как раз для этого.

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

Нет.

goto не может выше области в которой объявлен. А то, куда ты хочешь намекнуть — это что-то типа long_jmp с помощью которого в сишечке и эмулируют исключения.

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

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от PRN

зависеть от частоты происходящего

Невозможно угадать. Может быть залочено и пол часа, а может и 1 секунду — зависит от кол-ва задач на момент запуска.

flock

И зачем это тащить в зависимости?

если у тебя защита от повторных запусков в кроне

Не только в кроне, но и от шаловливых ручек.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

какой-то мудила - это дейкстра, по-моему.

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

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

какой-то мудила - это дейкстра

Ну и мудила значит. Вот именно в этом вопросе мудила. А в других вопросах — свет ясный. А в этом — мудила.

Мудила потому, что заботясь о птенчиках неразумных, которые могут наворотить хрен поми чего, он, говоря лишь рекомендательно, своим авторитетом раздул простую рекомендацию для говнокодеров в постулат вообще для всех, и для миддлов и для сеньёров. Так понятнее?

deep-purple ★★★★★
() автор топика
Последнее исправление: deep-purple (всего исправлений: 2)
Ответ на: комментарий от deep-purple

Невозможно угадать…

Похоже на штатную ситуацию. Исключения критикуют за их относительную медлительность при срабатывании. Поскольку почти вся «плата» за их использование перенесена именно на момент срабатывания. Хотя если приложение завершается, то все равно там исключение или код ошибки.

И зачем это тащить в зависимости? Там где есть cron это или что-то подобное есть из коробки.

Шаловливые ручки и другими способами все испортить могут. Но как защита от дурака лок в коде сработает.

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

Или вот на собеседованиях бывает часто. Дают бумажку с тестами. А там написан какой-то трип кислотный и вопрос — что выведет эта строка в результате? И несколько вариантов ответа. А я пишу вместо того чтобы обвести предполагаемый ответ: «Не знаю. Я так не пишу. Так только мудила написать может. Зачем вы у меня эту чушь спрашиваете? Я вот это вот говно напишу правильным и понятным способом. Просто скажите что надо получить в результате». Затем приходит какой-нибудь начальник отдела после изучения моих ответов и улыбаясь говорит: «Твоя правда. Тесты говно. Но мы это говно подсовываем чтобы совсем дебилов отфильтровать».

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от PRN

Исключения критикуют за их относительную медлительность при срабатывании

Как думаешь, сколько раз в секунду я их в своём коде вызываю?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от PRN

Вот честно, такое тоже бывает. Но только потому, что чья-то либа может бросить исключение при подсовывании ей на обработку элементов в цикле. И понятное дело, что ловить это придётся, иначе не сделаешь continue чтобы продолжить, отметив неудавшийся элемент.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

И несколько вариантов ответа. А я пишу вместо того чтобы обвести предполагаемый ответ: «Не знаю. Я так не пишу.

Одно из главных умений программиста - умение читать чужой код. Вы можете так не писать, но прочитать чужой код до вас должны.

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

Любой код может быть прочитан. А может ли он быть легко понят — вот где вопрос. Было дело, работали с кучей разных заказчиков. И там у каждого страшный говнокод и зоопарк технологий. И ту бац — появляется заказчик у которого все идеально. Я аж со стула стёк. В обход всех манагеров пишу ему письмо, мол, спасибо за код. А он мне в ответ: То то же! Спасибо за отзыв. Стараемся!

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Такой себе синглтон на уровне процессов. Годно выкрутился, наверно с исключениями выходит лаконичнее, чем с системой кодов результата выполнения (ака HRESULT).

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

Конечно. Так ты контролируешь что возвращает приложение и что оно может а что не может делать в конкретной ситуации. Без копипаст и прочего. Бросил исключение и забыл, т.к. там всё само разгребётся. Плюс ещё в логи можешь записать: «Я завержилсо, но без ошибки, потомучто», а в ОС или запускальщику отдать только код возврата.

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

У вас идея правильная, у вас толкование неправильное. Грубо говоря, ваш код сводится к

try {
    // . . .
    auto lock = acquire_lock();
    // . . .
} catch (LockFailed) {
    // another copy is already running
}
return 0;

и выбрасывание исключения из acquire_lock как раз сигнализирует об ошибке в acquire_lock. А уже на верхнем уровне, на месте вызова acquire_lock, вы принимаете решение о том, что вам делать с этой ошибкой. Для вас эта ошибка сигнализирует о том, что все в порядке, и вы просто возвращаете 0.

Вы же смешиваете acquire_lock и логику приложение в одно целое. Так делать не есть хорошо.

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

наверно с исключениями выходит лаконичнее, чем с системой кодов результата выполнения (ака HRESULT).

Я для этого придумал CheckRet.

#define CheckRet(_res) {status_t res = (_res); if (res < B_OK) return res;}
X512 ★★★★★
()
Ответ на: комментарий от deep-purple

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

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

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

Тут тоже получается ситуация похожая на твою - сфейлившийся тред, это исключительная ситуация с статусом sucess, которую надо просто правильно обработать.

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

Ну, натуральным развитием будет не return а break. Шобы из функций была одна точка выхода. Но, тогда надо бесконечным циклом пользоваться. И одно и другое - эмуляция goto без его явного использования.

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

Ну, натуральным развитием будет не return а break.

Тогда все функции придётся обвешивать do {...} while(false);, что не желательно и выглядит не очень. Это легко забыть написать. Для кодов ошибок можно настроить так, чтобы если возвращаемое значение не принимается, выводился warning. Также оно не может принимать коды ошибок.

Шобы из функций была одна точка выхода.

Если используется RAII, то это не проблема. Прямой вызов delete/close/release должен избегаться насколько возможно.

И одно и другое - эмуляция goto без его явного использования.

Так можно дойти до того, что return не в конце функции - это такое же зло как и goto.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 2)
Ответ на: комментарий от deep-purple

Что мешает использовать иксепшны в любых исключительных ситуациях включая успешные?

void insert_XY(Transaction & t)
{
    // Ожидаем вставку и X, и Y
    insert_X(t);
    insert_Y(t);
}

Если insert_X кидает SuccessException, то insert_Y не выполняется, хотя транзакцию логично закрыть как успешную. С другой стороны, если транзакцию откатить, то и insert_X откатится, хотя он кинул SuccessException.

Получается, единственный нормальный способ выполнить insert_X и insert_Y вместе заключается в ловле SuccessException. Ужас.

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

Одно из главных умений программиста - умение читать чужой код. Вы можете так не писать, но прочитать чужой код до вас должны.

Не должны. Именно по-этому никто не умеет писать на С++. Нужно знать как правильно писать и как правильно компилировать. 95% таких вопросов из тестов просто будут выдавать ошибку компиляции. А те кто пытаются читать и угадывать просто не знают как писать правильно, чтобы компилятор всё проверял.

fsb4000 ★★★★★
()
Ответ на: комментарий от deep-purple

Нет, не понятно. Я вообще не понимаю, при чем тут rethrow и goto. В приведенном примере оно никак не фигурирует.

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

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

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от Siborgium

Вы же смешиваете acquire_lock и логику приложение в одно целое. Так делать не есть хорошо

int retCode = 0;

try {
    try {
        // .......
    } catch (DBFailed) {
        throw AppException(DBFailed->context());
    } catch (LockFailed) {
        throw AppException(LockFailed->context());
    }
} catch (AppException) {
    retCode = AppException->retCode();
}

return retCode;

Сколько тут «логик»? Есть ли это хорошо? Где тут смешивание?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от PRN

Это надо упарываться

Без этого при обработке кодов возврата надо писать ещё больше.

каждый раз не забыть написать CheckRet

Можно выдавать warning если код ошибки не принимается: http://cpp.sh/3uaug.

Пока где-нибудь шутник не напишет

Чем это хуже #define true false?

X512 ★★★★★
()
Ответ на: комментарий от deep-purple

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

А rethrow здесь не имеет смысла. Ваш AppException буквально выполняет роль превращения исключения в error code, и больше ни для чего не служит. Может, где-то за кулисами меняет глобальное состояние (что делать в конструкторе исключения тоже далеко не best practices, даже с самых не-евангеличных точек зрения).

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

#define true false

Такой код не скомпилируется при правильных ключах компилятора, так как это ключевые слова С++…

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

внешний try бессмысленен

Нет. Вот блин, надо было написать полностью и развернуто. Там (на том уровне) можно бросить AppException если проблема действительно «глобального» характера.

Принятие решения об успешности исполнения функции у вас почему-то выносится в конструктор AppException

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

буквально выполняет роль превращения исключения в error code, и больше ни для чего не служит

Действительно, надо было написать развернуто, прям со всеми возможными кейсами. Чтоб вопросов больше не возникало. Ну а если сами пораскинете какую пользу эта конструкция может принести?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Короче ты в ту же степь что и EXL — давай чонить накрутим, лишь-бы иксепшны не пользовать.

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

ya-betmen ★★★★★
()
Ответ на: комментарий от X512

Обоснуйте почему нежелательно?

Процентов 95 своих функций так пишу, только не do-while, а

for(;;) {
  /*...*/
  break;
} 
. Потом, можно иметь разные развития, макросами вроде BreakOnError, ContinueOnWarning итд, и все какбы в единой системе.

nikitos ★★★
()
Ответ на: комментарий от ya-betmen

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

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от X512

Без этого при обработке кодов возврата надо писать ещё больше.

С исключениями еще короче:

#include <iostream>
#include <stdexcept>

void Do1() {printf("Do1\n"); }
void Do2() {printf("Do2\n"); throw std::runtime_error{"err"}; }
void Do3() {printf("Do3\n"); }

void Do()
{
	Do1();
	Do2();
	Do3();
}

int main()
try
{
	Do();
	return 0;
}
catch(const std::exception& e)
{
    std::cerr << e.what();
}

Можно выдавать warning если код ошибки не принимается

Начиная с 17-х можно юзать переносимый [[nodiscard]]

Чем это хуже #define true false?

Тем что в случае #define true false мне моя ide покажет подмену, а в примере выше мне надо будет ее искать)) А если еще учесть то что макросы не дружат с дебагером, то искать можно долго, в зависимости от фантизии написавшего.

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

А в каком-то другом месте лок семафора уже может быть и ошибкой.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Вот блин, надо было написать полностью и развернуто

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

Решение принимается с месте отлова, в данном примере только установкой актуального кода возврата.

…который попросту переписывается из AppException в retCode. В данном коде значение retCode зависит только от того, что вернет AppException::retCode();. Именно в конструкторе AppException это решение и принимается.

Нет. Он тупой и просто принимает контекст.

Нет. Он тупой, но на основе принятого контекста (и, возможно, глобального состояния) он еще и решает, что должно будет вернуть AppException::retCode().

Но можно добавить всякого

Можно. Зачем? Локальную ошибку обработайте локально, либо вообще не ловите, пусть раскручивается до глобального обработчика. Зачем выносить в конструктор исключения логгирование, обработку ошибок, etc?

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

Обоснуйте почему нежелательно?

  • Не принимается код ошибки. Иногда важно передать конкретный код ошибки, а не просто факт ошибки.
  • Замусоривается код.
  • Можно забыть написать for(;;) и т.п..
  • Может случится коллизия с обычным циклом и неожиданное поведение. CheckRet работает почти также как и исключения.

все какбы в единой системе

Какая-то переусложнённая система получается. В моём варианте одного макроса достаточно. Если не требуется возврат по ошибке, ошибку можно обработать явно через if и т.п..

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

А вот кстати лично мне такие вещи не нравятся. Но это просто к слову. Я понимаю зачем так делают. Если так уже написано, то и я буду мимикрировать под этот подход. Сам же такое писать не стану и напишу иначе. Но реагирую на это все абсолютно спокойно.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

когда лок семафора не удался

Ну так кантлоксемафор или что-то подобное.

А в каком-то другом месте лок семафора уже может быть и ошибкой

Ну так ты оттуда всё равно другую ошибку кидать будешь.

ya-betmen ★★★★★
()
Ответ на: комментарий от deep-purple

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

Своим примером я продемонстрировал гарантию, которую нарушает SuccessException: «В коде h1(); h2(); функция h2() выполняется всегда, если h1() выполнен успешно».

Ты предлагаешь убрать такую хорошую гарантию во всём коде только лишь потому, что в единичном случае тебе лень написать нормальный workflow. Почему во всём? Потому что сегодня твой код такой, завтра другой.

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

Обоснуйте почему нежелательно?

Потому что для этого придумали goto. Вы пишете (минимум) в два раза больше кода просто ради того, чтобы goto не использовать.

Siborgium ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.