4
\$\begingroup\$
class Program
{
    static void Main(string[] args)
    {
        var priceList = new List<int>() { 10, 20, 30, 40 };
        var totalAmount = InvoiceCalculator.CalculateTotalPriceWithTax(priceList, 5);
        Console.WriteLine(totalAmount);
    }
}

static class InvoiceCalculator
{
    private static int CalculatePrice(List<int> priceList)
    {            
        return priceList.Sum();         
    }
    private static int CalculateTax(int price, int taxRate)
    {
        return (price * taxRate / 100); // Ignore int datatype for simplicity. input values are immutable          
    }
    public static int CalculateTotalPriceWithTax(List<int> priceList, int taxRate)
    {
        int totalPrice = CalculatePrice(priceList); // input values are immutable
        int tax = CalculateTax(totalPrice, taxRate); // input values are immutable
        return totalPrice + tax;
    }
}

Features of the program are

  1. Inputs are immutable.
  2. Functions are not altering the state
  3. Use of pure functions
  4. CalculateTotalPriceWithTax is calling CalculatePrice and CalculateTax but not altering the state

• For simplicity I have used int datatype instead float, double for tax calculation.

Is it violating functional programming principle because CalculateTotalPriceWithTax() function is calling CalculateTax and CalculatePrice function?

Note: None of these calls are altering the state. For simplicity exception handling and aspects are ignored. Just interested in knowing the functional aspects of the program

\$\endgroup\$
1
  • 2
    \$\begingroup\$ I get that you use int for simplicity, but for accuracy you would want to use Decimal for any monetary based calculations. \$\endgroup\$
    – Rick Davin
    Dec 2, 2018 at 14:42

2 Answers 2

5
\$\begingroup\$

Hi and welcome to CodeReview.

You are right, your code does not modify state (has not side effects) and the output of the methods depends only from the input... Therefore I would guess that the functions are "pure functions".

However, I would prefere an IEnumerable of int instead of List of int as parameter type because with an IEnumerable the API shows that the method does not change the passed list.

If you value immutability, there are also some immutable collection in .net (e.g.: The ImmutableList).

If you like functional programming, F# is really worth a look! FSharpForFunAndProfit is a good point to start :D

\$\endgroup\$
3
\$\begingroup\$

This isn't functional. This is pure functions. In order for it to be functional you have to cut down the amount of statements var x = y; to the absolute minimum (since C# is not a pure functional language you won't be always able to remove them all), this means all methods should be extensions where possible. You also shouldn't hardcode the tax calculating function but pass it to the calculator. What if you wanted to calculate a different tax?

This is what I consider to be correct:

static void Main(string[] args)
{
    var priceList = new List<int>() { 10, 20, 30, 40 };
    var totalPriceWithTax = 
        priceList
            .TotalPrice()
            .AddTax(taxRate: 5, InvoiceCalculator.CalculateTax);

    Console.WriteLine(totalPriceWithTax);
}

static class InvoiceCalculator
{
    public static int AddTax(this int price, int taxRate, Func<int, int, int> calculateTax)
    {
        return price + calculateTax(price, taxRate);
    }

    public static int TotalPrice(this IEnumerable<int> priceList)
    {
        return priceList.Sum();
    }

    public static int CalculateTax(int price, int taxRate)
    {
        return (price * taxRate / 100);   
    }       
}
\$\endgroup\$
1
  • \$\begingroup\$ This is certainly an elegant way. AddTax method is calling InvoiceCalculator.CalculateTax function via calculateTax(price, taxRate) delegate.So ultimately you are calling function but via the use of delegate.Not sure why you are not calling the example mentioned in the problem as functional (in C# context) \$\endgroup\$
    – parag
    Dec 4, 2018 at 18:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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