Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why honest function example in C# still not being honest?

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?

like image 557
Kevin Tanudjaja Avatar asked Jan 26 '23 04:01

Kevin Tanudjaja


2 Answers

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.

like image 190
Sean Avatar answered Jan 31 '23 11:01

Sean


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);
    }
}
like image 25
xport Avatar answered Jan 31 '23 09:01

xport