3 ms·
Whilst some of the issues with C# are valid, it's totally possible to do monadic error handling in C#, I wrote an entire library to facilitate that [1]. In fac
by louthy 11y ago
Whilst some of the issues with C# are valid, it's totally possible to do monadic error handling in C#, I wrote an entire library to facilitate that [1]. In fact the big win of monadic error handling is the composable nature of monads:
Here's a function that throws an error on odd numbers:
Try<int> Number(int x) => () =>
{
if( x % 2 == 0 )
return x;
else
throw new Exception("Any exception");
};
Here the monadic computation succeeds, and 'res' holds 1000:
var res = match(from x in Number(10)
from y in Number(10)
from z in Number(10)
select x * y * z,
Succ: x => x
Fail: 0);
Here the monadic computation fails, and 'res' holds 0:
var res = match(from x in Number(10)
from y in Number(9)
from z in Number(10)
select x * y * z,
Succ: x => x
Fail: 0);
If you don't want to use it in a LINQ expression then you can just say:
var res = Number(10).IfFail(0);
There's also mention of the null problem, which obviously is a major problem with the language (and framework), but it can be tamed somewhat with Option<T> and TryOption<T>:
TryOption<int> Number(int x) => () =>
{
if( x % 2 == 0 )
{
if( x > 10 )
None;
else
return Some(x);
}
else
{
throw new Exception("Any exception");
}
};
Here the monadic computation succeeds, and 'res' holds 1000:
var res = match(from x in Number(10)
from y in Number(10)
from z in Number(10)
select x * y * z,
Some: x => x,
None: 0,
Fail: 0);
Here the monadic computation fails, and 'res' holds -1:
var res = match(from x in Number(10)
from y in Number(9)
from z in Number(10)
select x * y * z,
Some: x => x,
None: 0,
Fail: -1);
Here the monadic computation also fails because a None is returned, so 'res' holds 0:
var res = match(from x in Number(10)
from y in Number(20)
from z in Number(10)
select x * y * z,
Some: x => x,
None: 0,
Fail: -1);
So as you can see, using monadic error handling is doable in C# with the right tools. It certainly takes a bit more discipline from the programmer, but it's definitely worth it. It also makes your code declarative. A function that looks like this:
TryOption<string> DoStuff();
... clearly declares that the function may: Succeed, return 'no value', or fail. So you should deal with all 3 possibilities. In contrast, this doesn't give that information to the programmer:
string DoStuff();
[1] https://github.com/louthy/language-ext https://github.com/louthy/language-ext