Naios / continuable

C++14 asynchronous allocation aware futures (supporting then, exception handling, coroutines and connections)
https://naios.github.io/continuable/
MIT License
815 stars 44 forks source link

Trigger failure within continuation without using exceptions #49

Closed standardexe closed 2 years ago

standardexe commented 2 years ago

Hi @Naios,

I'd like to use this library in a project where we don't use exceptions. I can of course set an error using a promise, but is it somehow possible to have error logic in a normal continuable, like so:

do_stuff().then([](int result) {
    if (result < 0) return cancel();
    return 2*result;
});

Or is there maybe some other pattern I could use?

Thank you very much for all your work!

Naios commented 2 years ago

Hey, the library supports error handling without exceptions by definining CONTINUABLE_WITH_NO_EXCEPTIONS and CONTINUABLE_WITH_CUSTOM_ERROR_TYPE, take a look at https://naios.github.io/continuable/configuration.html. It is possible to define a custom error type that can be returned from any continuation by using rethrow.

standardexe commented 2 years ago

That's a quick answer, thank you :-) Maybe my initial example was a bit too vague. I figured out that I can customize the error type. However, this is what I'm currently trying to do, which gives me a compilation error:

#include <iostream>

class Error {
public:
    operator bool() { return true; }
};

#define CONTINUABLE_WITH_CUSTOM_ERROR_TYPE Error
#include "continuable/continuable.hpp"

auto do_stuff() {
  return cti::make_continuable<int>([](auto&& promise) {
    promise.set_value(-1);
  });
} 

int main() {
    do_stuff()
    .then(
        [](int result) {
            if (result < 0) return cti::rethrow(Error {});
            std::cout << "result: " << result << std::endl;
            return 2 * result;
        }   
    )   
    .then(
       [](int result) {
            std::cout << "result 2: " << result << std::endl;
       }
    )
    .fail(
        []() {
            std::cout << "fail!" << std::endl;
        }
    );

    return 0;
}

gcc 10.2.1 tells me following:

/home/arne/Documents/continuables/main.cpp: In lambda function:
/home/arne/Documents/continuables/main.cpp:59:22: error: inconsistent types ‘cti::exceptional_result’ and ‘int’ deduced for lambda return type
   23 |             return 2 * result;
      |                    ~~^~~~~~~~
/home/arne/Documents/continuables/main.cpp:59:24: error: no matching function for call to ‘cti::exceptional_result::exceptional_result(int)’
   23 |             return 2 * result;
      |                        ^~~~~~

So really my question is if this pattern can be supported by continuable in any way or if I'm just using it wrong and there is another way.

Naios commented 2 years ago

Well, you cannot return different types from a function, thats what the error is complaining about. Try returning cti::result<int> like:

    do_stuff()
    .then(
        [](int result) -> cti::result<int> {
            if (result < 0) return cti::rethrow(Error {});
            std::cout << "result: " << result << std::endl;
            return 2 * result;
        }   
    )   
standardexe commented 2 years ago

Ah, cti::result. Somehow I overlooked this. Thank you!