2

When using TryAsync in LanguageExt, you can do something like this...

static TryAsync<int> Divide(int n1, int n2) =>
    TryAsync(async () => {
      // Simulate some async operation that might fail
      await Task.Delay(300);
      return n1 / n2;
    });

I have the need for a similar method that returns an EitherAsync, but I'm stuck, as I can't find a static EitherAsync method to which I can pass an async lambda.

I know I can do this...

static EitherAsync<string, int> Square(int n) =>
  (n * n).AsTask();

...but that doesn't do anything async. If I change it to do this (simulate an async call)...

static EitherAsync<string, int> Square(int n) {
  Task.Delay(300);
  return (n * n).AsTask();
}

...then the call to Task.Delay is not awaited. I can't await it, as I can't make the method async (see this issue for more details).

I might be approaching this wrongly, but I can't see how you can await code inside such a method, which seems odd (to me, but that doesn't prove anything!), as the whole point of this monad is for async code.

Anyone know if it's possible to do something similar for EitherAsync? Thanks

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Avrohom Yisroel
  • 8,555
  • 8
  • 50
  • 106

2 Answers2

3

Any function function returning task should work due to implicit casts from T and Task<T> to Either, for example:

static EitherAsync<string, int> Square(int n)
{
    async Task<int> inner()
    {
        await Task.Delay(300);
        return n * n;
    }

    return inner();
}

Or you can manipulate with TryAsync mapping, which, I would say, is more correct approach because previous one will not handle exceptions thrown during the task execution:

static EitherAsync<string, int> Square2(int n) =>
    TryAsync(async () =>
        {
            await Task.Delay(300);
            throw new Exception();
            return n * n;
        })
        .ToEither(error => error.Message);
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • Thanks for the clear answer, and the suggested improvement. – Avrohom Yisroel Jul 07 '22 at 17:16
  • Just out of interest, is there any reason you newed up a `TryAsync` rather than using the static method like I showed. If you remove `new` from your code, it seems to work just the same. – Avrohom Yisroel Jul 07 '22 at 17:25
  • @AvrohomYisroel I wanted to show usage without static method. For me it does not compile without `new` (`Divide` also does not compile for me, not sure what am I missing, `Divide` compiles for me when `TryAsync` is completely removed to the left of `=>`, cause compiler will add `new TryAsync` in this case during compilation). – Guru Stron Jul 07 '22 at 17:32
  • 1
    Do you have `using static LanguageExt.Prelude` in your file, as you'll need that to get the static methods to work. – Avrohom Yisroel Jul 07 '22 at 17:39
  • @AvrohomYisroel yep, my guess was that forgot some static imports) – Guru Stron Jul 07 '22 at 18:00
  • I'm a bit stuck applying your suggestion to my real code. I opened [a new question](https://stackoverflow.com/questions/73100236/how-do-i-return-a-non-error-type-for-left-with-languageext-eitherasync), any chance you'd be able to take a look? Thanks again. – Avrohom Yisroel Jul 24 '22 at 18:01
3

There is an implicit conversion from a Task<T> to an EitherAsync<T, Anything> and an EitherAsync<Anything, T>, so you can just create a Task<T> using Task.Run to run any async code you'd like for example:

static EitherAsync<string, int> Square(int n) =>
    Task.Run(async () => {
        await Task.Delay(300);
        return n * n;
    });
Sweeper
  • 213,210
  • 22
  • 193
  • 313