Комментарии 13
Нет оператора ? , поэтому вложенные цепочки быстро превращаются в лапшу из лямбд.
Но вообще хорошо язык пошёл развиваться
Отсутствие ? можно компенсировать наличием корутин в языке. Один из примеров того, как это можно реализовать: https://gist.github.com/jemand2001/adb0cd09460bdcc44ca50e346eb7599c
Если оценивать по трём параметрам: размер кода, понятность и скорость работы, то особых улучшений не видно. Если ошибка является нормальным результатом работы функции, то каждый раз заполнять для неё целую структуру выглядит накладно. В этом смысле сишники давно изобрели errno, который можно и вообще не проверять, если уверен в результате. Цепочку лямбд неудобно отлаживать, и выглядит такой код не очевидно, и места они занимают много.
Цепочку лямбд неудобно отлаживать, и выглядит такой код не очевидно, и места они занимают много.
Ну это несколько странная телега. То что вы можете писать лямбды не требует от вас это делать - пишите обычные функции. Ну и отлаживать код с исключениями не сказать чтобы сильно проще, особенно в многопотоке.
В этом смысле сишники давно изобрели errno
оно на маленьком коде может и хорошо, но иметь некоторое глобальное состояние да ещё и в многопотоке, довольно заметный минус для оптимизатора - появляются неоптимизируемые индирекции. Ну и как в си гадать от кого из стека прилетело -1 вместо того чтобы явно видеть DbError::AccessDenied имеет свои следствия для безопасности финального кода.
Исключения дороги по производительности на throw‑path, требуют exception‑safe‑кода во всей цепочке вызовов, плохо взаимодействуют с многопоточностью
Не устану повторять, что в С++ принципы обеспечения exception safety прекрасно работают и для обычных return-ов. Поэтому если разработчик озадачился вопросами exception safety, то нет разницы, сообщается ли об ошибке через exception или через early return.
Спасибо за честную оценку ситуации, когда ошибка - исключительное явление, а не регулярное событие: ¨Для функций, которые вызываются миллион раз в секунду и почти всегда успешны, исключения дешевле (бесплатны на happy path).¨ Это надо учесть всем, кто задумывается о переходе на std::expected.
А будет режим, когда код не скомпилируется, пока не учтёшь возможные ошибки? Я так понимаю, в Rust это главная фишка. А то, вот это:
value() бросает исключение std::bad_expected_access если в expected лежит ошибка
Всю идею обесценивает. Такого быть просто не должно, компилятор должен за этим следить. Или, хотя бы, #pragma с форсом такого поведения добавить.
По идее, если всем этим функциям добавлять аттрибут [[nodiscard]] , то проигнорировать ошибку будет сложнее. С другой стороны, там же value() берётся, а на ошибку проверить могут и забыть...
В Rust .unwrap() на ошибке тоже паникует. Думаю, статические анализаторы смогут отловить отсутствие проверки перед вызовом. @Andrey2008?
Я извиняюсь, но разве в первом примере не надо добавить noexcept?
std::expected<int, ParseError> parse_positive_int(const std::string& input) noexcept {
//...
Хорошая попытка, но нет.
Почти идеальная реализация ошибок могла бы выглядеть примерно так, через structured binding (или destructuring, кому как нравится):
do {
auto [result, error] = TheService::callService(params);
switch (error) {
case TheService::ErrorCodes::TIMEOUT_REACHED:
System::fatal("TheService Not Available");
case TheService::ErrorCodes::RETRY:
System::sleep(TheService::DEFAULT_EXT_CALL_TIMEOUT);
break;
case TheService::ErrorCodes::OK:
return result;
}
} while (true); Код условный, реальный чуть посложнее будет. Но ключевой момент тут показан: TheService::ErrorCodes это enum c конечным числом значений. И если функция TheService::callService начинает еще какой-то четвертый тип ошибок возвращать (добавили еще одно значение в enum), то компилятор нам сразу высветит все switch места, где нет case обработки этого нового типа ошибки, и их нужно срочно пойти дописать.
А лямбдо-монады - это лишь синтаксический сахар, да есть есть весьма широкая категория любителей так спагетти-кодировать, и наверное нужно уважать их культурные отличия. Но проблему расширения контрактов, в данном случае возможных кодов ошибок, и проверку их соблюдения компилятором (покрытия всех возможных кодов) все эти чудесные трудно читабельные формы callback-ов не решают от слова никак, нужно идти и вычитывать код каждый раз.
std::expected в C++23: гайд по миграции с исключений на функциональный error handling