Search code examples
c#language-ext

LanguageExt - Error trying to Match on a method that returns TryAsync<Unit>


I am using a method in a library that returns a TryAsync<Unit> (dumb stupid implementation to show the signature)...

public TryAsync<Unit> DoLibraryStuffAsync() =>
  TryAsync(unit);

I want to call this, and return a Task<Either<string, Unit>>, where the string would contain the error message. I have got as far as this...

private async Task<Either<string, Unit>> DoMyStuffAsync() =>
  (await DoLibraryStuffAsync())
    .Match(_ => unit,
      ex => $"Ex: {ex.Message}");

However, this gives a compiler error on both of the branches in Match...

Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

Hovering over Match, I can see that the compiler has picked up on the overload that takes Funcs, so I would have expected to be able to return either a string or unit...

enter image description here

Anyone able to explain what I'm doing wrong, and how I fix it?


Solution

  • Whilst I can't offer a full explanation of the problem (as I don't completely understand it myself!), I can suggest how to fix it.

    I think the problem is that the compiler can't work out exactly what you're returning (no, I'm not sure why either!), but if you make it explicit, I think it will work...

    private async Task<Either<string, Unit>> DoMyStuffAsync() =>
      (await DoLibraryStuffAsync())
        .Match(_ => Right<string, Unit>(unit),
          ex => $"Ex: {ex.Message}");
    

    I would hope that someone can come along and explain to both of us why we need to do this, but at least this should get you going.

    Update

    OK, I discussed this with someone who understands this stuff better than I do (which is most people actually), and I think I have an idea why you got a compiler error.

    Consider the following silly method...

    Either<string, int> Jim() {
      Random r = new();
      return r.Next() % 100 > 50 ? 1 : "jim";
    }
    

    This compiles without needing to cast explicitly to an Either because both types that can be returned are in the same bit of code (ie the return statement).

    In your code, the two Funcs that you passed to Match were in separate pieces of code, so the compiler couldn't put them together and work out what the return type should be. I think this is because, although we humans can understand that both Funcs passed Match produce a return value for the same method, the compiler doesn't know that. It has no idea what Match does.

    Not sure that's completely clear, but I think it gives some idea why you needed to cast at least one of the return values.