Popularity
3.1
Declining
Activity
0.0
Stable
249
17
18

Description

A functional implementation of Either in C++14.

Programming language: C++
License: MIT License
Latest version: v0.5.0

neither alternatives and similar libraries

Based on the "Miscellaneous" category.
Alternatively, view neither alternatives based on common mentions on social networks and blogs.

Do you think we are missing an alternative of neither or a related project?

Add another 'Miscellaneous' Library

README

neither

A functional implementation of Either in C++14.

Travis GitHub license

buckaroo add github.com/loopperfect/neither

Examples

Handling Unsafe Code


auto unsafe = [] { // a function that throws, sometimes we can't avoid it...
  if (true) {
    throw std::runtime_error("error");
  }
  return 1;
}

Either<std::exception, int> e = Try<std::exception>(unsafe); // let's lift the exception into the typesystem

e.left()
  .map([](auto const& e) {
    return std::cerr << e.what() << std::endl;
  }); // print error if available

int result = e
  .leftMap([](auto) { return 42; }) // do nothing with exception and map to 42
  .rightMap([](auto x) { return x * 2; }) // do further computation if value available
  .join() // join both sides of either

ASSERT_TRUE(result == 42);

Another Example

Either<std::string, int> compute(int x) {
  if(x<0) return left("don't pass x<0");
  return right(x*x);
}

std::string resultString = compute(5)
  .rightMap([](auto x){ return x/2.0;}) // success case
  .join(
    [](auto errorStr) { return "compute said: " + errorStr; }, // error-case
    [](auto x) { return "compute said: " + std::to_string(x); } // success-case
   );

std::cout << resultString << std::endl;

Composition of Eithers


neither::Either<my_error_t, int> f1();
neither::Either<my_error_t, float> f2();

void compose() {
    auto value = f1()
        .rightFlatMap([](const struct_a& v){
            return f2();
        })
        .rightMap([](const struct_b& v){
            return 5;
        })
        .leftMap([](const auto& my_error){
            return 6;
        }).join();
    // value should be either 5 or 6
}

Maybe Example


Maybe<float> compute(float x) {
  if(x<0) return {};
  return {sqrtf(x)};
}

Maybe<float> x = compute(-4)
 .map([](auto x){ return x*x;})
 .map([](auto x){ return x+1 });

if(!x.hasValue) {
  std::cerr << "error occured" << std::endl;
}

Monadic Lifting


int sum(int x, int y){ return x+y; }

//...

auto monadicSum = lift(sum); // transforms sum to: Maybe<int> MonadicSum(Maybe<int>, Maybe<int>)

ASSERT_TRUE( monadicSum( maybe(5) , maybe(7) ).get(0) == 12 );
ASSERT_TRUE( monadicSum( maybe(), maybe(1) ).hasValue == false);

Why Eithers? - Learned Lessons About Error handling

Some useful references:

Summary and Conclusions

  • Error codes break composition
    • requires out-parameters; making functions impure and hard to reason about
    • using out-parameters makes inlining harder
    • => don't use output parameters
  • Exceptions are 2-3 orders of magnitude slower if exceptions are thrown
    • => avoid throwing exceptions - not always possible
  • Overhead of exceptions grows linear with the callstack
    • => catch exceptions early
  • Exceptions are not part of the type-system
    • annotating function signatures with throw and noexcept is not helpful; contract breaches are not detected in compile-time but call std::terminate in run-time
    • handling exceptions is error prone and requires documentation
    • => encode errors in the types to enforce proper handling by the API consumer

Installation

This library requires a C++ 14 compiler.

Install with Buckaroo:

buckaroo add github.com/loopperfect/neither

The Buck target is :neither

Alternatively you can copy & paste the headers to your include path:

cp neither/include/*.hpp $InstallPath/include/neither


*Note that all licence references and agreements mentioned in the neither README section above are relevant to that project's source code only.