1
\$\begingroup\$

I'm playing around with the concept of functional programming.

I have flattened the nested if statements and made by code more verbose.

The refactored code looks overly complicated.

What could be a simpler approach?

Nested Ifs

public static int Main(string[] args)
{
    int computer = 1;
    string brand = "PC";

    if (computer < 2)
    {
        if (brand != "Apple")
        {
            // perform complex calculation 1
            Console.WriteLine("you don't own a Mac");
            return 0;
        }
        else
        {
            // perform complex calculation 2
            Console.WriteLine("you own less than 2 Macs");
            return 1;
        }
    }
    else
    {
        // perform complex calculation 3
        Console.WriteLine("you own two or pcs");
        return 2;
    }
}

Flattened Main

public static int Main(string[] args)
{
    int computer = 1;
    string brand = "PC";

    return CalculatedResult = DetermineComputer(computer, brand);
}

Extension Methods

public static class extensions
{
    public static int ComplexCalc1(this bool val)
    {
        Console.WriteLine("you don't own a Mac");
        return 0;
    }
    public static int ComplexCalc2(this bool val)
    {
        Console.WriteLine("you own less than 2 Macs");
        return 1;
    }
    public static int ComplexCalc3(this bool val)
    {
        Console.WriteLine("you own greater than two pcs");
        return 2;
    }
    public static int ComplexCalc4(this bool val)
    {
        Console.WriteLine("Condition not accounted for");
        return -1;
    }

    public static bool IsLessThanTwo(int computer) => computer < 2;

    public static bool IsApple(string brand) => brand == "Apple";

    public static (Func<bool, int> func, bool result) IsLessThanTwoAndNotApple(this int computer, string brand)
        => (ComplexCalc1, IsLessThanTwo(computer) && (IsApple(brand) == false));

    public static (Func<bool, int> func, bool result) IsLessThanTwoAndIsApple(this int computer, string brand)
        => (ComplexCalc2, IsLessThanTwo(computer) && IsApple(brand));

    public static (Func<bool, int> func, bool result) Unaccountedfor(this int computer, string brand)
        => (ComplexCalc4, true);

    public static (Func<bool, int> func, bool result) IsGreaterThanTwoAndIsNotApple(this int computer, string brand)
        => (ComplexCalc3, (IsLessThanTwo(computer) == false) && (IsApple(brand) == false));
}

Calculation

public static int DetermineComputer(int computer, string brand)
{
    var methodlist = new List<(Func<bool, int>, bool)>
    {
        computer.IsLessThanTwoAndNotApple(brand),
        computer.IsLessThanTwoAndIsApple(brand),
        computer.IsGreaterThanTwoAndIsNotApple(brand),
        computer.Unaccountedfor(brand)
    };

    var tupleResult = methodlist.Where(x => x.Item2 == true).Select(x =>
        new {
            functor = x.Item1,
            result = x.Item2
        }).First();

    return tupleResult.functor(tupleResult.result);
}

Unit Tests

[DataRow(3, "Apple", -1)]
[DataRow(2, "Apple", -1)]
[DataRow(1, "Apple", 1)]
[DataRow(0, "Apple", 1)]
[DataRow(3, "PC", 2)]
[DataRow(2, "PC", 2)]
[DataRow(1, "PC", 0)]
[DataRow(0, "PC", 0)]
[DataTestMethod]
public void NestedIfs_Demo(int first, string second, int expected)
{
    int computer = first;
    string brand = second;

    var CalculatedResult = DetermineComputer(computer, brand);

    Assert.AreEqual(expected, CalculatedResult);
}
\$\endgroup\$
3
  • 2
    \$\begingroup\$ The current question title, which states your concerns about the code, applies to too many questions on this site to be useful. The site standard is for the title to simply state the task accomplished by the code. Please see How do I ask a good question?. \$\endgroup\$
    – BCdotWEB
    Nov 8, 2020 at 18:10
  • \$\begingroup\$ (@PeterCsala: The formatting of the code presented is one aspect to review: please don't change it (beyond fixing "markdown mistakes"). While I think the (small) rest of your suggested edit useful, it seems to lack substance. The "edit pitch" gives Because community members review edit as a reason, which won't apply once you surpassed 2k rep.) \$\endgroup\$
    – greybeard
    Nov 10, 2020 at 10:42
  • \$\begingroup\$ @greybeard It was approved by the OP. But if you think adding and removing white spaces aren't appropriate then I'm sorry. \$\endgroup\$ Nov 10, 2020 at 10:57

2 Answers 2

2
\$\begingroup\$

I'm assuming that computer and brand are meant to be function parameters, otherwise any kind of branching would be unnecessary. Here's something that pretty much does what you want, assuming you just want messages that describe in clear english the quantity and brand of computers, and not necessarily have the exact messages used in your examples:

public static void Message(int quantity, string brand)
{
    Console.WriteLine("You own " + quantity + " " + brand + (quantity !== 1 ? 's' : '');
}

The actual brand and quantities are variables that are inserted into the general message. If you want the message to be longer and use more variables, then you would probably want to create substrings to later be combined, for the sake of readability:

public static void Message(int quantity, string brand)
{
    string brandPlural = brand + (quantity !== 1 ? 's' : '');

    Console.WriteLine("You own " + quantity + " " + brandPlural;
}
```
\$\endgroup\$
2
\$\begingroup\$

The functional way to solve this problem is actually with pattern matching. My solution to do exactly as you showed would look something like this:

    public static int ComputerType(int computer, string brand)
    {
        var (result, message) = (computer, brand) switch
        {
            (var n, var b) when n < 2 && b != "Apple" => (0, "you don't own a Mac"),
            (var n, _)     when n < 2                 => (1, "you own less than 2 Macs"),
            _                                         => (2, "you own two (or more) pcs or Macs")
        };
        Console.WriteLine(message);
        return result;
    }

But there are additional problems with your solution. You shouldn't need to hardcode any values, for instance.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.