vkhorikov / CSharpFunctionalExtensions

Functional extensions for C#
MIT License
2.46k stars 305 forks source link

Question: How to use linq query syntax for Result types #566

Open christophercalm opened 2 months ago

christophercalm commented 2 months ago

Is the Select method not supported for linq query syntax for result?

As an example here is code that works with Maybe

Maybe<string> name = "John";

var upper = from x in name select x.ToUpper();`

But does not work with Result

This is the error: CS1936 Could not find an implementation of the query pattern for source type 'Result'. 'Select' not found.

I see the that SelectMany operation is supported but it looks like there is no select. Is this something that you would be open to me adding?

It would help with workflows like this

Result<string> GetGreetingMessage(string userName)
{
    var maybeGreeting =
        from name in ValidateName(userName)   // Bind the validated name
        select CreateGreetingMessage(name);   // Map to a greeting message

    // Convert Maybe to Result
    return maybeGreeting.ToResult("Invalid name provided");
}

Maybe<string> ValidateName(string name)
{
    // Check if the name is valid, return Maybe.None if invalid
    return string.IsNullOrWhiteSpace(name) ? Maybe<string>.None : Maybe<string>.From(name);
}

but for results.

vkhorikov commented 2 months ago

We're trying to keep naming consistent in this library. In the earlier days there were discussions on which naming approach to choose: the C# one (Select, SelectMany, etc) or the F# one (Map, 'Bind', etc). We decided to follow the F# naming convention because it's more consistent (e.g SelectMany doesn't really make sense for Result and even for Maybe).

So all Select extensions remaining should really be marked as obsolete and redirected to Map.

The downside to this decision is that Linq expressions (from ... in ... select) won't work anymore, but people rarely use those. And I suggest to just use regular linq instead.

christophercalm commented 2 months ago

The reason for using linq expressions is that you can combine results from many different monads. You can’t do that with the regular linq syntax without multiple select many expressions. I would ask that you please reconsider as the rest of the api is complete in regards to the overloads for linq query expressions.

vkhorikov commented 1 month ago

OK, makes sense. Feel free to submit a PR. A couple of implementation notes:

  1. Select should call Map internally; SelectMany -- Bind (just so that we don't have duplicate implementations)
  2. Please leave a note as to why we have Select and SelectMany -- to support linq expressions
christophercalm commented 1 month ago

OK, makes sense. Feel free to submit a PR. A couple of implementation notes:

  1. Select should call Map internally; SelectMany -- Bind (just so that we don't have duplicate implementations)
  2. Please leave a note as to why we have Select and SelectMany -- to support linq expressions

https://github.com/vkhorikov/CSharpFunctionalExtensions/pull/567/commits/9a80bf2c1e5f9314c85dd7274e117e17f5846f2e

That has been done in this commit.

vkhorikov commented 1 month ago

Would you be able to raise a PR for this commit? Just select your branch here: https://github.com/vkhorikov/CSharpFunctionalExtensions/compare and hit "Create pull request"

christophercalm commented 1 month ago

Would you be able to raise a PR for this commit? Just select your branch here: https://github.com/vkhorikov/CSharpFunctionalExtensions/compare and hit "Create pull request"

I have one here. :)

https://github.com/vkhorikov/CSharpFunctionalExtensions/pull/567

vkhorikov commented 1 week ago

Sorry for the delay. Merging, will be published soon.