nekronos / ResultSharp

Result type for C#
MIT License
5 stars 3 forks source link

Result.TryAsync? #7

Open vitidev opened 1 month ago

vitidev commented 1 month ago

I don't see a way to achieve this without adding a method to ResultSharp. Something like...

public static async ValueTask<Result<T, E>> TryAsync<T, E>(Func<Task<T>> fn) where E : Exception
{
    try
    {
        var value = await fn();
        return Result<T, E>.Ok(value);
    }
    catch (E exception)
    {
        return Result<T, E>.Err(exception);
    }
}

public static ValueTask<Result<T, Exception>> TryAsync<T>(Func<Task<T>> fn) =>
    TryAsync<T, Exception>(fn);
nekronos commented 1 month ago

Thanks for opening an issue. The C# Task API is kinda an implementation of Results + async, as a Task contains state like Result value, Exception etc.

I have not thought about how ResultSharp may implement an async API or if it even should.

Do you have a more concrete example of what you are trying to achieve?

vitidev commented 1 month ago

@nekronos

public Result<int, Error> Handle(MyModel myModel)
{
    var validateResult = validator.Validate(myModel);
    if (!validateResult.IsValid)
        return Result<int, Error>.Err(...);

    try
    {
        var id = SomeOperationWithException();
        return Result<int, Error>.Ok(id);
    }
    catch (Exception e)
    {
        return Result<int, Error>.Err(...);
    }
}

I can replace it with sugar

public Result<int, Error> Handle(MyModel myModel)
{
    var validateResult = validator.Validate(myModel);
    if (!validateResult.IsValid)
        return Result<int, Error>.Err(...);

    return Result.Try(() =>SomeOperationWithException()).MapErr(...);
}

But there is no sugar for async

public async Task<Result<int, Error>> HandleAsync(MyModel myModel, CancellationToken ct)
{
    var validateResult = await validator.ValidateAsync(myModel, ct);
    if (!validateResult.IsValid)
        return Result<int, Error>.Err(...);

    try
    {
        var id = await SomeOperationWithExceptionAsync();
        return Result<int, Error>.Ok(id);
    }
    catch (Exception e)
    {
        return Result<int, Error>.Err(...);
    }
}

if it even should.

c# is not rust. c# have exceptions. And concept "async/await" is part of the language and is actively used. For example, asp.net core is completely async. And result monad is actively used there. The only difference is in the implementation of result monad. The implementation may not have sugar try, but if it does, then the async option is also needed.

how ResultSharp may implement an async API

Just add async. My code in the question is working code, only for this I have to fork the library You have to decide Task/ValueTask and Try/TryAsync.