Здравствуйте, antropolog, Вы писали:
A>код возврата OpenFile. Я зову асинхронно функцию OpenFileAsync, передаю ей коллбек для возврата результата. Коллбек on_result(FILE). У меня не возникло проблем. Проблемы у тебя, где поставить try catch.
Я тебя понял — ты (КЕП!) пытаешься показать, что асинхронный механизм с синхронным плохо совмещается. Но почему-то приплетаешь сюда исключения. Но это не проблема исключений. Это всё равно, что я буду говорить, что коды возврата отстой, потому что я хочу получить получить код возврата сразу при передаче коллбека, а он мне не даёт! Это не проблема кодов возврата как и не проблема исключений.
Ещё раз — исключение передаёт информацию о проблеме выше по стеку вызовов — где стек вызовов в асинхронной модели? Вот то то же и оно.
Во вторых, если как ты говоришь OpenFileAsync — функция асинхронная, она просто не может использовать синхронный механизм, то есть исключения она бросать не может. Она должна вернуть тебе std::future, который прозрачно бросит исключение при доступе к данным.
В третьих, если у тебя полностью всё асинхронное, то никаких on_result(FILE) быть не должно, так как обработка ошибок должна вестись в асинхронном режиме тоже. Должно быть on_success и on_fail, в коллбек параметра которого пихается код/объект проблемы. Но это не код возврата, тут возврата нет, потому и проблем с ними нет. Тут проблемы другого рода.
В полностью асинхронной программе архитектура должна быть быть такой, чтобы все проблемы можно было обработать на месте возникновения, что сильно ограничивает область её применения, либо архитектуру (к примеру, полностью событийная архитектура, где ни коды возврата, ни исключения не используются).
A>я хочу понять как сделать хорошо с исключениями
Выбираешь точки обработки ошибок и пишешь в оптимистическом ключе. Гораздо проще чем использовать коды возврата.
P>>std::promise/std::future
A>зачем мне эти инструменты? Это монады для вытаскивания отложенных значений. В моём примере коллбек зовётся только тогда, когда результат (или его отсутствие) уже готов. Зачем здесь promise/future?
Это то, с помощью чего достигается совмещение асинхронного и синхронного кода на плюсах.
A>Смотри:
A>
A>optional<DATA> loadData(filename) {
A> optional<DATA> data;
A> if ( optional<FILE> f = OpenFile(filename) ) {
A> // OK. File is found.
A> data = ReadFromFile(*f);
A> }
A> else if ( optional<NETFILE> f = OpenFileFromNetwork( config::get_remote_url() + filename) )
A> {
A> // Otherwise, try to open file from network share
A> data = ReadFromNetFile(*f);
A> }
A> else if ( optional<FILE> f = OpenFile("default.file") )
A> {
A> // Otherwise, try to read data from the default file
A> data = ReadFromFile(*f);
A> }
A> else if ( optional<NETFILE> f = OpenFileFromNetwork(config::get_remote_url() + "default.file") )
A> {
A> // Otherwise, try to read data from the default file from network
A> data = ReadFromNetFile(*f);
A> }
A> return data;
A>}
A>
A>Очевидно, что для клиентского кода, ошибка в случае OpenFile и ReadFromNetFile вполне ожидаема, и для неё отдельные бранчи. Как loadData будет выглядеть в случае с исключениями?
Ну, типичный индусский код — наличие файла проверяется косвенным способом, loadData выполняет не столько load сколько поиск файла, данная сигнатура не позволяет клиенту узнать почему нет данных — то ли файл не нашли, то ли он был пустой и могли искать дальше. Как этот код прошёл у вас ревью непонятно.
А где собственно обработка кодов возврата? Её тут нет.
Или ты считаешь, что bool — это и есть код возврата? Тогда понятно, почему не видишь проблем, возникающих с ними.
Возвращение bool подразумевает ветвление, что означает возможность локальной обработки. Фактически bool — это не исключительная, а штатная ситуация.
Вот пример, что такое коды исключений:
https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa365430(v=vs.85).aspx , а вот возможные значения
https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms681381(v=vs.85).aspx .
И их надо обрабатывать для каждой функции. Потом, в случае проблемы передать наверх по стеку для для обработки. Учти, что клиентская функция как правило использует не одну, а несколько функций + имеет и свои проблемы, о которых должна сигнализировать с помощью кодов возврата. И всё это добро надо доставить в нужное место, так как чрезвычайно редко в реальных программах проблему возможно адекватно обработать на месте её возникновения.
A>Вот это новости. Правильно ли я понимаю, что я должен всегда чекать всё, что потребуется OpenFile, чтобы она ненароком не выкинуло исключений? (ну там, наличие файла, права доступа, количество доступных файловых хендлов в системе, итд ).

Я даже не знаю что тебе на это ответить. Нет. Ты должен обеспечить наличие всего требуемого ещё до вызова loadData, а что не смог обеспечить — то проверить в процессе.
(Иначе получается ситуация: сел поесть, но оказалось что на котлете нет подливы, как собственно и котлеты, да чего уж — и тарелка отсутствует, и сидишь не на кухне, и даже не у себя дома)
A>Но даже с синхронными вызовами, какого типа исключения должен ловить фремворк, например, который зовёт твои функции? (Подсказка: Откуда он будет знать про твои типы исключений? И про boost::exception?
)
Фреймворк предоставляет свой набор исключений, который ты можешь использовать либо как есть, либо наследуясь от них.