Pull to refresh

Comments 19

У меня ощущение, что go произвел на Александреску впечатление.
Тут и defer-ы появляются и try-catch критикуются.
Может, наоборот, учитывая время выхода статей? :)
Эти defer'ы реализованы в языке D вместе с исключениями (поэтому в отличие от одного defer в Go, в D целых три ключевых слова — scope(exit), scope(success) и scope(failure) — для общего случая, выхода без исключения и выхода по исключению, что видимо и позаимствовано в Boost.ScopeExit и здесь). А сама концепция подозреваю что более древняя чем реализации Go, D и Boost, наверняка в каких-нибудь теоретических трудах есть.
К слову говоря, файловые операции весьма условно могут быть «транзакционно стабильными».
То что файл закрылся без ошибок, не означает что он вообще будет записан.
https://fgiesen.wordpress.com/2015/10/25/reading-and-writing-are-less-symmetric-than-you-probably-think/
Я, может быть, торможу, но вся статья ведь построена на предположении, что мы ловим «catch(...)» и вообще никак не обрабатываем определённые типы исключений — а где это вы такое в нормальном продакшн-коде видели?
Тормозите, исключения прокидываются на уровень выше. Плохим стилем же обычно считается безусловное игнорирование исключений (catch(...){})
Ну, если они прокидываются, то мы всё-равно приходим к необходимости написания ифа или свича в зависимости от их типа, плюс обработки того самого catch(...). В итоге у нас будет весь тот же самый код, только расположенный чуть выше и со странным никому не известным макросом вместо всем известного и входящего в стандарт try\catch. И в чём выигрыш?
Разница в акцентах использования. Если try/catch в каком-то смысле эквивалентно проверке if(result != 0)/else, то scope задает в начале блока действия которые надо выполнить при любом выходе, успешном выходе и/или неуспешном выходе из области видимости. Просто еще одна абстракция на ступеньку выше. Однако я поглядел быстренько на D код, да, там этот стиль используется очень широко и действительно сильно меняет вид кода.
Макросы конечно неуклюжи и вряд ли будут использоваться в таком виде. Как я понимаю идея доклада — то что в C++ уже сейчас тоже возможен такой стиль написания и при внесении небольших изменений в синтаксис языка это станет нативной фичей.
А то что стандарт теперь прямо рекомендует избегать чрезмерного использования try/catch вас не удивляет? Еще совсем ведь недавно даже явная спецификация типов исключений была рекомендованным стандартом и тоже ее отмену многие в штыки встречали.
В нормальном продакшине и throw под запретом. Мы же не на каком-то богохульном java пишем. throw только для использования внутри драйверов при обработке аппаратных исключений.
throw — совершенно нормальный и очень удобный механизм перехвата ошибок из глубины вложенных функций, альтернатива ему — бесконечная лента проверок возвращаемого значения которая масштабируется гораздо хуже, от слова совсем. В продакшне бывает под запретом что угодно, но как правило это волевое решение менеджера, который либо вообще далек от написания кода, либо прочитал лет… дцать назад книжку где ему так посоветовали. Я бы не стал называть «нормальной» команду где исключения под запретом, хотя легко могу себе такое представить.
Я работал в нескольких компаниях из топ 100 — ни у кого там даже в мыслях нету писать в предложенном вами стиле.
И это не капризы менеджеров.

Да, Гугль тоже можно причислить к ненормальным.
Гугль — это

1. легаси
2. максимальное упрощение, идущее на пользу в масштабах корпорации

Для того, чтобы равняться на Гугль, надо быть гуглем
Естественно, это не библиотека и к использованию в продакшне не предназначено. Это — концепция, которая как я предполагаю будет где-то обкатана, в том же бусте например и потом предложена к включению в стандарт.
Да, Гугль тоже можно причислить к ненормальным
я наверное что-то не понял, это здесь вообще к чему?
Потому что это нерабочая концепция. Может в виде учебных примеров и красиво а в жизни малоприменимо.
Microsoft отказался примерно к 2005 году от такого стиля — и вот почему.

Я когда extended stored procedures отлаживал под MSSQL2000 — у меня шторма исключений в дебагере пролетали, к счастью в MSSQL2005 от этого отказались и на курсах Microsoft настоятельно таким стилем не рекомендовали пользоватся.

Забуду я где оттрайкетчить вызов из такой библиотеки и упадет мой сервер в самом неожиданном месте.
Не обижайтесь только, вы по-моему не поняли концепции. Забудьте про макросы, они используются только потому что в текущей версии C++ без них не обойтись. Пусть у нас будут, как в D, языковые конструкции scope exit, skope success и scope fail. С try/catch они не связаны напрямую вообще никак, но пусть у вас в теле некоторой функции определены три оператора:
scope exit {… }
scope success {… }
scope fail {… }
Эта функция так или иначе когда-нибудь завершится, если это будет нормальный выход, то будут вызваны первые два функтора; если будет выброшено исключение, то оно будет где-нибудь поймано и тогда в нем будут вызваны первый и третий функтор. Александреску утверждает что это мощная концепция которая будет очень к месту в C++ и я с ним полностью согласен, не в том смысле что она заменит собой все остальное, а в том что будет еще один полезный архитектурный элемент.
А насчет того что посоветовала Microsoft в 2005 году… Этого стиля тогда просто не было и быть не могло.
Во-первых C++ в 2005-м был совсем другим и я сомневаюсь что кто-то мог тогда дать осмысленный совет для 2015. А во-вторых, мы с Вами примерно ровесники (и похоже даже дважды земляки), я например помню как они яростно боролись с TCP/IP, потом с std::string и еще чем-то там из std::, потом еще с чем-то..., короче они не пророки, в этой области по крайней мере, как впрочем и ни одна из крупных современных компаний. В общем совет от Microsoft 2005 года сегодня на путеводную звезду никак не тянет.
А где здесь декларативное программирование? Слова scope, control flow как-то не вяжутся с ним. Да и потом, опять кучи макросов, которые выглядят громоздко.
Я может чего-то не понимаю, и вообще статью не читал, но SOLID-ный дизайн с использовнием RAII выглядит вот так

struct Temporary
{
    ~Temporary() {
        remove(path);
    }
    const ::path path;
};

void copy_file_tr(const path& from, const path& to) {
    Temporary tmp {to+".deleteme"};
    copy_file(from, tmp.path);
    rename(tmp.path, to);
}


При этом, естественно, и с move_file все сразу становится проще
Ну так это оно и есть, если вы еще не заметили все метапрограммирование сводится к тому чтобы вместо таких вот классов, создаваемых специально для каждого случая предоставить готовый универсальный шаблон.
Раз уж вы не читали, я специально для вас скажу суть в двух предложениях:
— В узкотехническом смысле, вдобавок к макросу SCOPE_EXIT, который известен уже 15 лет минимум, скоро можно будет добавить еще два — SCOPE_SUCCESS и SCOPE_FAIL используя новую функцию int uncaught_exceptions(), которой еще правда нет, но появится в C++17.
— В широком архитектурном смысле, использование этих трех конструкций позволяет писать на C++ в декларативном стиле, и приведены иллюстрации как это может выглядеть.
На самом деле это все.
Универсальный шаблон и так уже есть — unique_ptr со своим Deleter. Ну то есть технически вы можете сделать
std::unique_ptr<const char, decltype(remove1)*> autodelete(tmp.c_str(), remove);
Но даже это не нужно, потому чтоTemporary — вполне самостоятельный класс, и совершенно непонятно, почему это не нужно его выделить?

А уж использовать ужасные С-ные SCOPE* вместо RAII просто дикость какая-то на мой взгляд
Sign up to leave a comment.

Articles