Ensure returns Success instead of Failure
yarecky1 opened this issue · comments
Hi,
I spent a long time trying to figure it out why my method doesn't work as expected.
This works as expected resulting in x is false
. Ensure returns Failure<bool>
.
var r1 = Result.Success(false)
.Ensure(x => x == true, "x is false")
.Tap(x => Console.WriteLine("x is true"))
.TapError(error => Console.WriteLine(error));
But this doesn't work resulting in x is true
which is very confusing. Ensure returns Success<bool>
.
var r2 = Result.Success(false)
.Ensure(x => x == true) // <- no string error
.Tap(x => Console.WriteLine("x is true"))
.TapError(error => Console.WriteLine(error));
The only difference is in 2nd line where Ensure doesn't have error string parameter. This is confusing to everybody who doesn't expect this behaviour. Could you take a look and secure it if possible? Let me know what you think, please.
Thanks
Jarek
Hi, there'are two overloads
Result<T> Ensure<T>(this Result<T> result, Func<T, bool> predicate, string errorMessage) // used in the first example
Result<T> Ensure<T>(this Result<T> result, Func<T, Result<T>> predicate) // used in the second example
As you may see, the first overload accepts Func<T, bool>
, while the second overload accepts Func<T, Result<T>>
. So the C# compiler silently translates x => x == true
into x => (Result<bool>)(x == true)
because an implicit cast is defined from T
to Result<T>
in a way that T t
is translated into Result.Success<T>(t)
, so you return a success Result<bool>
from the "predicate"
(parameter name is really horrible, because predicates can only return bool
) and technically the behavior is correct.
I didn't believe that such a mature library can have a bug, so I read the library. I analysed both methods after - by pure accident - I decided to write 2nd argument as an error string. This doesn't change the feeling that this "bug" (my bug) is very hard to find. And I presume that it is very hard to find for anybody who is not very familiar with the library and use the overload in a wrong way only because it allows for it - like me, who didn't take care about error string, only about the result.
Another similar example is this below, with error string, but with the same result, it returns a Success instead of Failure.
var r1 = Result.Success(false)
.Ensure(x => x = true, "x is false") // = instead of ==
.Tap(x => Console.WriteLine("x is true"))
.TapError(error => Console.WriteLine(error));
You don't want to know how long it took me to find this missing =
.
I stronly recommend you to do two things
- Do not do
x == true
andx == false
. Use justx
and!x
instead - Add some analyzers (like
SonarAnalyzer.CSharp
which has this diagnostic that will be reported forx = true
code) and use<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Regarding the issue you've mentiones I'd say that it's not a bug in the library itself. And since this (probably confusing) behavior occurs only when typeof(T) == typeof(bool)
I think it's very niche and should not be fixed in any way.
1. Do not do `x == true` and `x == false`. Use just `x` and `!x` instead
I know, it's lame, I did it during searching solution to quickly see statement and error message. I tried many different options and left this statement causing more problems to me.
2. Add some analysers (like `SonarAnalyzer.CSharp`...
Will do, thanks.
...<TreatWarningsAsErrors>true</TreatWarningsAsErrors>`
Temporary switched off. I'm switching ancient project from VB.NET to c#, have 800+ warnings and messages after conversion, converter applies == true or == false everywhere. Right now I'm just testing different libraries.
Thank you for help and explanations!