Git Product home page Git Product logo

cat's Introduction

CAT

contributions welcome
C# abstract types - dotnetstandard 1.0

- Inspired by FP, F# lang and ROP -

Why Cat?

This small library with no dependencies at all (except dotnetstandard) was born from the interest of having maybe/option and result/choice types in C#, without having to reference bigger library, and in a sort of "simplified" way. So it's just some interfaces, implementations and a few handy extension methods, you are welcome for contributions and filing/spotting issues!

Option

Simulates a Maybe/Option type with generics and interface inheritance. IOption<T> exposes bool property .IsSome . Some<T> and None<T> both implement IOption<T>. I kept the generic constraint on None<T> because I think it can anyway help the compiler figure out and not mix up different "nones".

Result

Simulates Choice/Either type via generics and interface inheritance.

Result.Strict

Strict version has more static "strictness", meaning you need to provide more type constraints, but then type inference will work its magic out when possible. IResult<TOk,TError> exposes bool .IsSuccess, TOk .AsSuccess and TError .Error.
You will get a runtime exception if you try to access .Error on a Success<TOk,TError> and .AsSuccess on a Failure<TOk,TError> instance .

Result.Loose

Loose is more dynamic, skipping some typechecks, it's a light-weight version, but be aware of your types, it is more likely to throw at runtime for invalid casts.
IResult exposes bool .IsSuccess and is implemented by Success<T> and Failure<T>. You will need to cast or make use of the "as" operator when converting back to the concrete type from IResult, thus providing the generic type constraint.

Then

Both option and result types were given a .Then extension method, which in a way (for the little I know) emulates the monadic bind operator, making available the "unwrapped" result to the next computation, or just returning to the end of the "pipeline" if the option is None, or if the result is Failure.

ThenLift

Results types supports .ThenLift method for cases where the next step in the pipeline might want to return an IResult/IResult<TOk,TError> too, it's not wrapped internally, that's why I named it Lift: is going from a type T to a lifted-wrapped type W<T>. If you try to pass an IResult returning function to a .Then method for the Loose type, as a continuation, it will throw you an ArgumentException "use ThenLift instead!".

Status

build status

CatCat

https://www.nuget.org/packages/CatCat/

Usage

Option

Here is some basic usage of the IOption<T> type. Please note that null references, as well as Nullable<T> where T is a value type and null strings, are all converted into None<T>.

var r = "not null".ToOption()
              .Then(z => "hello")
              .Then(x => "1")
              .Then(x => Int32.Parse(x) as int?)
              .Then(x => DateTime.Now)
              .Then(x => null as string);

if (!r.IsSome)
{
    Console.WriteLine("r is None");
}
else
{
    Console.WriteLine($"r is Some!: {r.UnwrapSome()}");
}

let's now consider a service which might fail with an exception during invokation, it will come handy when considering the use of the Result types.

public class ServiceWhichMayFail
{
    public string CallWhichMayFail(bool fail)
    {
        if (fail)
            throw new Exception("fail");

        else return "ok";
    }
}

Loose Result

Here is a wrapped version of that same service first:

public class WrappedService
{
    private readonly ServiceWhichMayFail service;

    public WrappedService(ServiceWhichMayFail service)
    {
        this.service = service;
    }
    public IResult CallWhichMightFail(bool fail)
    {
        try
        {
            return service.CallWhichMayFail(fail).ToSuccess();
        }
        catch (Exception ex)
        {
            return ex.ToFailure();
        }
    }
}

and we can then proceed to use the IResult and .Then/ThenLift extensions as follow:

var x = new WrappedService(new ServiceWhichMayFail());

var result = x.CallWhichMightFail(false)
    .Then<string, int>(s => 3)
    .ThenLift<int>(z => x.CallWhichMightFail(false))
    .ThenLift<string>(z => x.CallWhichMightFail(true))
    .ThenLift<string>(z => x.CallWhichMightFail(false));

if (result.IsSuccess)
{
    var r = ((Success<string>) result).Data;
    Console.WriteLine($"success: {r}");
}
else
{
    var ex = ((Failure<Exception>) result).Error;
    Console.WriteLine($"failure: {ex}");
}

Strict Result

and now let's see the different behaviour of strict result, once we wrap again our "could-be" failing service, wrapped with a strict IResult, which has more static type checking, thus providing better type inference in method chains:

public class WrappedServiceStrict
{
    private readonly ServiceWhichMayFail service;

    public WrappedServiceStrict(ServiceWhichMayFail service)
    {
        this.service = service;
    }
    public IResult<string,Exception> CallWhichMightFail(bool fail)
    {
        try
        {
            return service.CallWhichMayFail(fail).ToSuccess<string,Exception>();
        }
        catch (Exception ex)
        {
            return ex.ToFailure<string,Exception>();
        }
    }
}

and now the usage, you can see that is no more necessary to declare the type constraints in .Then calls (type inference works):

 var x = new WrappedServiceStrict(new ServiceWhichMayFail());

var result = x.CallWhichMightFail(false)
    .Then(s => 3)
    .ThenLift(z => x.CallWhichMightFail(false))
    .ThenLift(z => x.CallWhichMightFail(false))
    .ThenLift(z => x.CallWhichMightFail(false))
    .Then(_ => 43);

if (result.IsSuccess)
{
    var r = result.AsSuccess;
    Console.WriteLine($"success: {r}");
}
else
{
    var ex = result.Error;
    Console.WriteLine($"failure: {ex}");
}

Let me know any improvements/issues, feel free to pr.

cat's People

Contributors

jkone27 avatar

Watchers

 avatar  avatar

cat's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.