from this reference : http://functionalprogrammingcsharp.com/honest-functions
I have learned to be more honest when defining method/function in C#. It said that prefer pure function so that the function will always give the exact return type given in signature.
However when I try to apply it:
int Divide(int x, int y)
{
return x / y;
}
From the website:
The signature states that the function accepts two integers and returns another integer. But this is not the case in all scenarios. What happens if we invoke the function like Divide(1, 0)? The function implementation doesn't abide by its signature, throwing DivideByZero exception. That means this function is also "dishonest". How can we make this function an honest one? We can change the type of the y parameter (NonZeroInteger is a custom type which can contain any integer except zero):
int Divide(int x, NonZeroInteger y)
{
return x / y.Value;
}
I'm not sure what is the implementation of NonZeroInteger, they don't seem to give any implementation of NonZeroInteger in the website, should it check for 0 inside that class? And I'm pretty sure if I call Divide(1, null) it will still show an error, thus making the function not honest.
Why honest function example in C# still not being honest?
Taking the example you've posted, and having read the link, if you want to make the function "honest" then you don't really need to create a new type, you could just implement the Try
pattern:
bool TryDivide(int x, int y, out int result)
{
if(y != 0)
{
result = x / y;
return true;
}
result = 0;
return false;
}
This function basically fulfills the "honest" principle. The name says it will try to do division, and the resulting 'bool` says that it will indicate it is was successful.
You could create a struct NonZeroInteger
but you're going to have to write a lot of code around it to make it act like a regular numeric type, and you'll probably come full circle. For example, what if you pass 0
to the NonZeroInteger
constructor? Should it fail? Is that honest.
Also, struct
type always have a default constructor, so if you're wrapping an int
it's going to be awkward to avoid it being set to 0.
To make it honest, define a new data structure and check the status.
enum Status { OK, NAN }
class Data
{
public int Value { get; set; }
public Status Status { get; set; }
public static Data operator /(Data l, Data r)
{
if (r.Value == 0)
{
// Value can be set to any number, here I choose 0.
return new Data { Value = 0, Status = Status.NAN };
}
return new Data { Value = l.Value / r.Value, Status = Status.OK };
}
public override string ToString()
{
return $"Value: {Value}, Status: {Enum.GetName(Status.GetType(), Status)}";
}
}
class Test
{
static Data Divide(Data left, Data right)
{
return left / right;
}
static void Main()
{
Data left = new Data { Value = 1 };
Data right = new Data { Value = 0 };
Data output = Divide(left, right);
Console.WriteLine(output);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With