language-ext
language-ext copied to clipboard
Replace current Result<T>.Match syntax
Why not create something like the following? Your current Result<T>.Match
/ IfSucc
syntax looks a bit weird and so is the name IfSucc
.
if (result.IsSuccess)
{
var data = result.Data; // compiler won't comply for nullability issues because it was successful
}
if (result.IsFaulted)
{
var error = result.Error; // compiler won't comply for nullability issues because it was faulted
}
instead of
_ = result.IfSucc(data =>
{
// that way I could access the data but it ain't as pretty as the one above.
});
I assume the reason you didn't is because you were not aware of the MemberNotNullWhen
/NotNullWhen
attributes.
public sealed record CallResult<T>(
[property: MemberNotNullWhen(true, nameof(CallResult<T>.Data))]
[property: MemberNotNullWhen(false, nameof(CallResult<T>.Error))]
bool Success, T? Data, Error? Error)
{
public CallResult(T data) : this(true, data, default)
{
}
public CallResult(Error error) : this(false, null, error)
{
}
}
public abstract record Error(int? Code, string Message, object? Data);
Even tho this post is a bit older, I'm gonna answer it out of my knowledge for anyone reading this and asking this himself, too.
-
Result<> isn't a fully implemented monad in this library, it is just a pure return value of the Try<>-monad. The Try-monad is supposed to be matched directly instead of invoking it.
-
MemberNotNullWhen-Attribute got introduced in .NET 5. LanguageExt is netstandard 2.0. Additionally the Try<> and Result<> monads are way older and got more or less replaced since introduction of the Eff<> and Aff<> monads
-
Even when you using those attributes: If you use it that way you are reintroducing problems we're happy to got rid of the functional way: You are generating boilerplate code and therefor lot of code noise just to check safe access for properties, and the possibility of an unsafe access is back again. And if the possibility of unsafe access is there, sooner or later there WILL be an unsafe access.
When you use monads you rather want to produce so called railroaded code: Stay in the monads by using map and bind functions, lift pure values up to them and keep this up until you reach the end of the application. Monads aren't supposed to be unwrapped after every operation
@MrWuffels You've got the job ;)
Maybe a little irrelevant to this, but may I ask why in the Match
function, the left is handled on the right and the right is handled on the left? Thanks!
@wxxedu Which Match
function are you referring to? This issue is around Result<A>
which has Succ
and Fail
parameters (and Result
has been deprecated in v5
, so I'd advise moving away from it and to Fin<A>
).
If you mean the Match
on Either
then that would be a separate issue. In v5
you'll see that the parameters have been swapped for Either
.
It is however good practice to use named parameters when using Match
, so you can have the order whatever way makes sense to you:
var result = either.Match(
Left: l => ...,
Right: r => ...);
This labelling of parameters is more declarative and makes code easier to read for others (with no cost overhead).
In v5
you can also use C#/s pattern-matching:
var result = either switch
{
Either.Left<L, R> l => ...,
Either.Right<L, R> r => ...,
};
Hi @louthy, thanks so much for the quick and detailed reply. Yes I was meaning the Either
type, sorry for the omission. I realised we did not update the version of the package, and were using the older version. Thanks so much for your help!