It?s possible that the post title above left you scratching your head. ?Functional programming in C#. Is that even a thing?? Well, it?s definitely a thing. Allow me to clarify.

Most people would classify C# as an object-oriented language, but it?s possible that you, as a .NET/C# developer, have been using functional programming concepts without even knowing it.

Make no mistake.? Using functional-programming-inspired features is not the same as programming in a pure functional language, like Haskell. Or even a hybrid language but with stronger emphasis on the functional side, like F#.

However, employing functional programming concepts can improve the quality of your code.? And that?s what today?s post is about.

I?ll?just first briefly cover the attractions of functional programming and why it makes sense to apply it even when using a so-called object-oriented language.?

Then I’ll show you how you?ve already been using some functional style in your C# code, even if you?re not aware of it.

I’ll tell you how you can apply functional thinking to your code in order to make it cleaner, safer, and more expressive.

Want to know if you're getting it right as you learn C#? Download a free trial of CodeIt.Right and get an instant, automated code review.

C# Functional Programming: Why?

We know the .NET framework offers some functional capabilities in the form of the LINQ extension methods, but should you use them?

To really answer this, we need to go back a step and understand the attraction of functional programming itself.?The way I see it, the easiest path to start understanding the benefits of functional programming is to first understand two topics: pure functions and immutable data.

Pure functions are functions that can only access the data they receive as arguments and, as a consequence, can’t have any side effects.??Because of these properties, pure functions are predictable, easier to reason about and intrinsically testable.

Immutable data are just objects or data structures that, once initialized, can’t have their values changed, making them easier to reason about and automatically thread-safe.

As a C# developer, you already employ immutability on a day-to-day basis, since several types in the .NET BCL are immutable. The System.String class is probably the most famous of them, but don?t forget the types related to date and time, such as DateTime, DateTimeOffset and Timespan.

And of course, the structs that represent primitive data such as int, boolean, decimal and so on are also all immutable. It wouldn?t even make sense to change the number 5, right?

Fundamental Functional Programming Operations and How to Perform Them Using C#

With the what and why of functional programming out of the way, it’s time to get to the how.

l’ll be covering three fundamental functions: map, filter, and reduce. I’ll start by showing some use cases, then I’ll show a traditional, procedural way of solving the problem. And finally, I’ll present the functional way.

C# Map

In simple terms, the ?map? operation takes a sequence of items, applies some transformation to each one of those items, and returns a new sequence with the resulting items. Let?s see some examples.

Suppose you wrote the following code, due to a customer?s demand:

static void AddThreeToEachElement(int[] arr) { for (var i = 0; i < arr.Length; i++) { arr[i] += 3; } }

It?s a function that adds three to each element of the given array of integers. Pretty straightforward.

Now a request for a new function comes in. This time, it should add five to each element in an array. Ignoring the rule of three, you jump right ahead into a generalized version, parameterizing the number to be added:

static void AddNumberToEachElement(int[] arr, int n) { for (var i = 0; i < arr.Length; i++) { arr[i] += n; } }

Then yet another request comes in. Now you must write a function that will multiply each element of the given array by, let?s say, three. I won’t add the code sample now because I’m sure you’ve got the picture.

By now, you should know better than to hardcode the number, so you’d probably jump ahead to a general version right away. Even then, some duplication would still exist: the loop itself.

Hmm…what if you could keep just the loop and instead parameterize the action to be applied on each item?



The Functional Way

Take into consideration what you?ve just read about pure functions—and also your previous knowledge of programming best practices in general—and think of ways the code could be improved.

From my perspective, the main problems are

The code is too specific . It can?t be easily changed to accommodate other transformations being applied to the array elements. It just performs a sum, and that’s it.

Too much boilerplate. Look at the previous sample again. Count the lines. There are seven, of which only one really concerns itself with carrying through the business logic of the method.

How would the functional way improve on this? That?s the way I?d write the first example in F#, for instance:

let result = Seq.map (fun x -> x + 3) numbers

I?m assuming here that “numbers” is a sequence of integers I?ve got somehow. Then I use the map function on the Seq module, passing the sequence as a parameter, along with a function that takes an int and adds three to it.

The Functional Way, .NET/C# Flavor

.NET implements the map operation in the form of the ?Select? LINQ extension method. So you could rewrite the F# example above like this:

var result = numbers.Select(x => x + 3);

One important point that needs explaining is that the type of the resulting sequence doesn?t need to match the type of the source sequence.

Do you have a list of ?Employee? and need a sequence of ints (containing, for instance, their IDs)? Easy peasy:

List<Employee> employees = EmployeeRepository.All(); IEnumerable<int> ids = employees.Select(x => x.Id);

C# Filter

I think filter is, hands down, the easiest operation of the bunch. It has a very intuitive name, and the need for filtering stuff is so common in programming that I bet you correctly guessed what it is just by its name (if you didn?t know it already).

For the sake of completeness, though, let?s define it. The filter operation…wait for it…filters a sequence, returning a new sequence containing just the items approved by some criteria.

The Imperative Way

Since we?ve used employees in the previous section, let?s keep within the theme. Let?s say you need to come up with a list of the employees who have used at least three sick days.

In a more procedural style, you?d maybe write something along the following lines:

public static List<Employee> GetEmployeesWithAtLeastNSickdays(List<Employee> employees, int number) { List<Employee> result = new List<Employee>(); foreach (var e in employees) ?? { ???? if (e.Sickdays >= number) ???? { ???????? result.Add(e); ???? } ?? } return result; }

I wouldn?t say there?s something definitely wrong with this code. The method’s name is a bit too long, but it’s very descriptive. The code does what it promises. And it’s readable enough.

But similarly to the previous section, we can make the argument that the code is too noisy. We can say that, essentially, the only line that does something domain related is the if test. All the other lines are basically boilerplate-y infrastructure code.

Can a functional approach help us here?

The Functional Way

Let’s rewrite the method above by using LINQ:

public static List<Employee> GetEmployeesWithAtLeastNSickdays(List<Employee> employees, int number) { return employees.Where(x => x.SickDays >= n).ToList(); }

Here we use the “Where” extension method, passing the filtering criterium as a delegate. To be honest, the outer method became not very useful since it just delegates the work. In real life, I’d get rid of it.

C# Reduce

Reduce is often the one many developers have some difficulty understanding. But it isn’t hard at all.

Think of it like this: you have a sequence of something, and you also have a function that takes two of these “somethings” and returns one, after doing some processing.

Then you start applying the function. You apply it to the first two elements in the sequence and store the result. Then you apply it again to the result and the third element. Then you do it again to the result and the fourth item, and so forth.

The classical example of reduce is adding up a list of numbers, so that’s exactly what we’re going to do in our example.

The Imperative Way

So, suppose we’re to sum a bunch of integers. We could do it like this:

public int Sum(IEnumerable<int> numbers) { var result = 0; foreach (var number in numbers) { result += number; } return result; }

At this point, you’re probably familiar with what I have to say about this code: it isn’t necessarily wrong, but it’s inflexible and noisy. Can functional programming save us?

The Functional Way

In .NET/C#, the “Reduce” operation assumes the form of the “Aggregate” extension method. This time, I’ll just get rid of the enclosing method and write the LINQ solution right away:

var sum = number.Aggregate((x, y) => x + y);

Things look a little bit more complex here, but don’t get scared. In this case, we’re just passing a function that takes two parameters, instead of one, like in the previous examples. It has to be that way since the function must be applied to two elements of the sequence each time.

But as it turns out, there’s an even easier way of solving this particular problem (adding a bunch of numbers). Since summing a sequence of numbers is such a common use case, there’s a dedicated method to do just that. It’s called, not surprisingly, “Sum”:

var sum = numbers.Sum();

What’s “Aggregate” good for, then? Well, adding a list of integers is just one of the applications for reduce, but you’re not in any way restricted to only that. You can use it with any binary operation, such as concatenating strings or summing custom types.

The Verdict: Is the Functional Approach Better?

After these examples, you might be wondering if the “functional” way is any better? It’d be extremely hard to define what “better” is, so I won’t even bother. Let’s consider another criterion: readability.

Though we know that code readability can also be highly subjective,?I’d say that yes, the functional examples are more readable. Suppose we need to retrieve and sum all the salaries from employees with more than five years of company time. We could easily do that by writing a loop, in which we’d test the condition and accumulate the salary if the test turned out true.

Or we could just write this:

var sum = employees.Where(x => x.CompanyTimeInYears > 5).Select(x => x.Salary).Sum();

I honestly believe this line to be more readable (and generally better) than the procedural approach. It’s more declarative; it shows the intention of what we’re trying to get done without being too concerned with the how.

It almost reads like natural language: “The list of employees where their time in the company is greater than five years, select their salary and sum them”.

Add Some Functional Spice to Make Your Code Tastier

Many people use LINQ for years without even realizing they’re using functional programming concepts. I take this as proof that functional programming isn’t beyond the capabilities of the enterprise developer who lacks a strong background in math.

Some of the concepts presented here are neither new nor restricted to functional programming. The benefits of distinguishing between functions that produce side effects from those that don’t is the basis of principles like command-query separation (CQS), for instance.

By the way, it bears repeating: employing functional-like features in a language like C# isn?t really the same as using a more full-fledged functional language.

For example, at first sight, F#?s pattern matching may not look a whole lot different than C#?s switch. But when using pattern matching, F#?s compiler will give you a warning if you forget to match some option.

And since you should treat warning as errors, that?s a handy feature to avoid bugs that would otherwise creep in to maybe be caught by unit tests afterwards.

Haskell, as a pure functional language, enforces the separation between code that produces side effects and code that doesn?t, so you?re basically forced to design your code in such a way that takes the maximum advantage of pure functions.

The goal of this post was not to teach you functional programming. This is honestly beyond my capabilities, as I’m still studying it myself. And besides, there are awesome resources for that purpose if you want to learn more.

Instead, what I wanted here is to give you a little taste of what a functional style can do for your code, which is to make it more expressive, concise, and declarative. Now it’s up to you to try to apply the functional mindset to the code you write.

Learn more how CodeIt.Right can help you automate code reviews and improve the quality of your code.

About the author Carlos Schults Contributing Author Carlos Schults is a .NET software developer with experience in both desktop and web development, and he?s now trying his hand at mobile. He has a passion for writing clean and concise code, and he?s interested in practices that help you improve app health, such as code review, automated testing, and continuous build. You can read more from Carlos at carlosschults.net. This author does not have any more posts.

Share this: Twitter

Facebook

LinkedIn

Email

Print

