C# functional extensions NuGet library



I’ve created a NuGet package out of the functional extensions I wrote about in this post series and in my Pluralsight course.

C# functional extensions NuGet library

Thanks to one of the listeners of my Functional C# course, I finally made a separate NuGet package which is based on the Result class I wrote about awhile ago.

The package contains the following classes:

  • Result
  • ResultExtensions
  • Maybe
  • MaybeExtensions
  • ValueObject

These classes allow you to compose multiple operations into a single chain:

public HttpResponseMessage Promote(long id)

{

    return _customerRepository.GetById(id)

        .ToResult(“Customer with such Id is not found: “ + id)

        .Ensure(customer => customer.CanBePromoted(), “Unable to promote”)

        .OnSuccess(customer => customer.Promote())

        .OnSuccess(customer => _emailGateway.SendEmail(customer.PrimaryEmail, customer.Status))

        .OnBoth(result => result.IsSuccess ? Ok() : Error(result.Error));

}

That is basically an adaptation of the Railway programming approach for C#.

This coding style is quite useful but has a major challenge. That is, there are a lot of different variations of the OnSuccess, OnFailure, and OnBoth extension methods. They differ subtly for various use cases and it might become quite hard to figure out which one you need to introduce in your own code base to make the chain work.

The idea behind the NuGet package is to alleviate this burden and gather all overloads for OnSuccess, OnFailure, and OnBoth extension methods in a single place so that you don’t need to do this work yourself.

You can find the source code here and the package itself – here.

At the moment, there are not a lot of extension methods, but it’s a good point to start from. If you see a use case which is not supported by the existing overloads, leave a comment below describing your situation and I’ll add appropriate extensions to the library. Or send me a pull request if you prefer to add them yourself.

Share




  • Franco Lázaro

    Hi from Argentina Vladimir.
    I didn’t know the ROP programming style, it seems pretty simple, I’ll check it.

    Your posts about functional programming made me start to read about, well, functional programming. I like the idea of having immutable, testable, well focused functions.

    Keep it up!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thanks Franco!

  • Jonathan Dennis

    Hi Vladimir,

    Thanks so much for making this NuGet package. I have been using Functional.Maybe for a while now. But your package includes additional functions. The result object especially looks very interesting. I will check it out for sure. Thanks.

  • https://github.com/Mykezero Mykezero

    I’ve been using a version of your result class for quite some time now; Definitely going to check out the new library. Thanks for putting this together!

  • GeorgeVovos

    One of my favorite Pluralsight courses.
    Really good work and easy to understand,I’ve recommended this course to others.
    Many thanks

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thank you!

  • farhad

    Hi Vladimir,

    I wanted to get your opinion regarding the way Maybe type is implemented by Mr Zoran Horovat in his course, by having it implement IEnumerable so that it can be enumerated against to allow the optional execution of code against the value within the Maybe type. this essentially allows for getting rid of the check on the Maybe type to see if it has a value before executing code on that value by utilising a ForEach extesion method on IEnumerable and optionally executing the code against each item in the Maybe type(in this case there is only one or none).

    Also, if you think it is a valid implementation can this be done by making the Maybe Type implement the IEnumerable interface through a partial class?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Implementing IEnumerable in Maybe allows to quickly get access to the LINQ extensions but I don’t think it’s a good way to implement Maybe.

      While both Maybe and IEnumerable are monads, they are different kinds of monads, I don’t recommend conflating them. It’s basically the same issue as with Maybe vs Result. While Maybe technically can be used in place of Result (and vice versa), their semantics differ and conflating them would bring confusion.

      I recommend implementing genuine Where/Select/etc. methods instead. They are not that hard to implement anyway. For example, the ForEach scenario you mentioned can be implemented using the Execute method:


      _repository.GetById(id) // returns Maybe
      .Where(x => x.Name == "Some name") // also returns Maybe
      .Execute(x => x.Promote()); // returns void

      Here are the implementations of these methods:
      https://github.com/vkhorikov/CSharpFunctionalExtensions/blob/master/CSharpFunctionalExtensions/MaybeExtensions.cs

  • Neil Newman

    Another +1 for your course and this nuget package.

    I have had lots of conversations about and recommended your course. As you mention in another post the distinction between Maybe and Result is subtle, but I think it is very important not to conflate them. Maybe is about not having a value for good valid reasons, rather than Result which is about not giving back a value because something went wrong, or is invalid because of business rules.

    Thanks for sharing…

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thank you! The way you put the distinction between Maybe and Result is exactly the way I think of it too, great explanation!

  • Neil Newman

    during development it occurred to me that we could have a static single instance of the vanilla ok result. A bit like string.Empty that means we do not create lots of instances. A small gain to be sure, but might make a difference if we use this approach a lot in a vary large application.

    private static readonly Result OkResult = new Result(true, string.Empty);

    public static Result Ok()
    {
    return OkResult;
    }

    as long as Result is fully immutable I don’t see any problem with this.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Absolutely. Will make a change to Result now, will go live with the next NuGet package version.

  • Neil Newman

    Hi

    just an idea when using Result. I thought it might be useful to have an implicit operator to avoid having to type .Value

    public static implicit operator T(Result result)
    {
    return result.Value;
    }

    Still thinking about this, but it does seem to work well. It is unnecessary if you are railway’ing using the Result extensions.

    Means I can get back a Result of double and then just use it without typing result.Value

    e.g.

    double answer = myMathsFunction(previousResult);
    double square = answer * answer; //Obviously check it was successful 🙂

    rather than
    double square = answer.Value * answer.Value;

    Interested in your thoughts…

    As we are using the railway approach as much as possible I have not put this into production and have not found a use case where it has helped, but thought it was interesting.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Neil, interesting suggestion!

      I would recommend not to do that, though. Implicit conversion operators are for operations that perform smoothly, without any chance to fail. For example, when defining an Email value object, it’s ok to create an implicit conversion from Email to string, because the set of all correct emails is a subset of all strings, so the conversion always succeeds: https://github.com/vkhorikov/FuntionalPrinciplesCsharp/blob/master/New/CustomerManagement.Logic/Model/Email.cs#L42

      In the example with Result, you do need to check if a result was successful before getting the value out of it (trying to access Value for a failed result should raise an exception), so implicit conversions wouldn’t fit here.

      • Neil Newman

        When you put it that way, I tend to agree. Probably why I have been reluctant to put it into production, and have not found a good use case for it…

        Just because you can do something, does not mean you should 🙂

  • Neil Newman

    Hi Vladimir, other than the default constructor issue, what are the reasons for Result not being a struct, and might it be worth accepting the limitations in an environment where structs might give you a performance advantage.

    Also interested in your thoughts on when to use structs in general.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Neil,

      The other disadvantage is that they don’t support inheritance and thus you would need to re-implement some parts between the generic and non-generic versions of Result. BTW, in the latest version of the lib, Result has been turned into a struct. So that’s a good example where those shortcomings were accepted due to performance and inherit non-nullability advantage 🙂

      Regrading structs in general, I think you need to use them whenever you can (make sure though that all your structs are immutable, mutable structs can lead you to a trouble pretty quickly). I usually use them for simple supplementary immutable things or where I don’t need to work with big ORMs (they don’t support mapping to structs).

  • Neil Newman

    Hi Vladimir, we have been using Result in a legacy code base and often find we nee to draw a line where we unwrap the value and the client code of the method expects a value or a specific default value. E.g. a string.Empty if the name was not available

    I found the code a bit clumsy to check IsSuccess so I wrote UnwrapOrDefault. this extension unwraps an Ok result or returns the type default on failed. I also wrote one to take your own default value.


    [DebuggerStepThrough]
    public static T UnwrapOrDefault(this Result result)
    {
    return result.IsSuccess
    ? result.Value
    : default(T);
    }

    [DebuggerStepThrough]
    public static T UnwrapOrDefault(this Result result, T defaultValue)
    {
    return result.IsSuccess
    ? result.Value
    : defaultValue;
    }

  • http://draptik.github.io/ draptik

    Thanks for your excellent blog and pluralsight courses!

    Why is the `Error` property in `Result` of type `string` (and not f.ex. `object` or `TError`)?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      That’s a shortcoming I haven’t yet addressed. The library started as a collection of small and simple helper classes, hence the Result of string which is useful but mainly in simple scenarios only.

  • Steve Chadaway

    Hi Vladimir,

    I’ve just started using this library, thanks for the fantastic knowledge share!!! Just one thing I’m missing before I can fully implement project wide, hoping you can suggest either a workaround or we can implement it with an extension.

    Issue is with form validation where we need to return a dictionary of keys and error messages (or similar structure), to show property and error key/value pairs in order to report property level validation back to the user.

    Can I extend this library (and just use the nuget package) to do this or would I need to get the full code down?

    Thanks!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Steve. There’s no such functionality at the moment, unfortunately. If you come up with some solution that could be fairly universally applied to other projects, let me know please, I’ll add it to the library.

      • Steve Chadaway

        I’ve been working on something exactly like that, maybe it could be a good candidate for one of your code reviews?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          For sure, feel free to submit it!