Maxim Goncharuk.NET Developer

Functional Programming in C#


Why functional programming?

It’s not a secret that Object Oriented Programming (OOP) is a dominating paradigm and a lot of best practices are built around the interaction between objects. But for the last few years, Functional Programming (FP) has been becoming more and more popular among developers.

FP was originally invented in mathematical circles in languages like Haskell, Lisp, and Erlang. Soon this style began to interest a wide mass of developers because of its brevity and elegance. But it was hard to understand all the charm of the functional approach 30 years ago - immutability and a huge amount of small functions largely affected computer performance.

Nowadays it’s no longer a problem. Speaking of .NET, you can see that a lot of useful features come to C# from F#: LINQ, query expressions, async flow, higher order functions, pattern matching, etc. (by the way, here is a good article about pattern matching in C# 7). Why are they so useful? Because they help us focus on business logic instead of thinking about core infrastructure, state changes, concurrency and parallelism issues.

Moreover, in the near future, the physics of the hardware architecture won’t allow increasing processor speed, so concurrent processing will be the common way to add performance. However, OOP techniques cannot take advantage of multiple processors at once because of shared data and mutable state. Using functional programming, the computer can run several functions at once because those functions are not altering outside state information.

Probably for these reasons, the creators of C# provide us more and more opportunities to do it. Using the functional programming way allows us to:

  • Write less boilerplate code;
  • Write more safe methods;
  • Manage concurrency and parallelism;
  • Test the codebase more easily.

As you may know, the .NET community treats the functional paradigm with caution. Perhaps that's why we do not have a fully-fledged functional backend framework yet. And I do not insist that you rewrite your project using a huge set of functions. Rather, I recommend using as many functional features as possible within an OOP framework, such as ASP.NET MVC.

In this article, I’m going to show you several approaches that, in my opinion, can make your life much easier. Some of them you may find contentious and not applicable, but I hope you will treat them with understanding and will derive the maximum benefit from reading about them.

The State Problem

I think many of you will agree that one of the most serious obstacles in enterprise development is managing the state of a part or the whole application correctly. Each developer who works with a multithreading system has spent enough time looking for an error when one thread changes a state while the second thread tries to read the result. This is a common issue in concurrent and parallel programming. But in general, you may find state issues in different places. For example, the next class has a huge set of dependencies and each method uses only one of them:

So if you want to get a list of users, you should initialize tons of objects which you won’t use. Moreover, the garbage collector will gather all these objects and freeze the whole server. Another problem you may face is when you use some sort of Builder or State patterns and change their content in different places.

In this example, the order of method calls is important and you have to control which function goes first and which is next. In the worst case, the builder’s state could be changed in several different methods and you will spent a lot of time debugging to find the method that caused an error. The easiest way to decrease the count of methods which interacts with a state is to use pure functions. In the next section, I’m going to rewrite examples above in a stateless way.

Make your server stateless

“Pure function” is a function that doesn’t change any values from arguments. It returns the same result every time you call it with the same set of arguments. The term “pure functional” came from impure functional programming languages, the foremost among them being Lisp. Lisp's design was based fundamentally on functional programming. However, it also allowed side-effects as a pragmatic choice. So, in Lisp, one mostly wrote "pure functions”, but occasionally, one wrote "impure functions," i.e., functions with side-effects, to get something done.

The terms "pure Lisp" or "purely functional subset of Lisp" have been in use for a long time. Slowly, by osmosis, this idea of "purity" has come to invade all of our space. In C#, every method could be a “pure function”, but I suggest using static methods to prevent using the state of the class. Let’s rewrite the first example with static methods:

Suppose we don’t have any other methods. Then we can go further and make the whole class static:

To get the most benefit, I suggest using as many static methods as possible. Also, if your class is like a service and doesn’t have any fields or properties, you should mark it as a static class. In the OOP world, it is generally accepted that using static methods is an anti-pattern. You can find a lot of arguments about this, but I like the idea from this post at stackoverflow that if you use static methods without touching global or shared data then you can avoid a lot of issues.

There are two important things you should remember using static methods:

  • Don’t use any static data (fields or properties) except constants. Using static data, you’ll get many more problems than if you don’t use static at all.
  • Using static methods, you can’t mock your dependencies. In this case, you have two options: create wrappers (I’ll describe below) or use frameworks like Moles, JustMock or TypeMock.

Static methods are very good for testing because you don’t have to care about any state issues or dependencies. You just put several arguments into the function and it returns the same result every time you call it. But as your application grows, sooner or later you’ll need some dependencies (databases, remote API’s, etc). The easiest way to test your code with dependencies is to split the method into two parts: a business logic and a dependency’s initialization.

Let’s look at the following simple example on how to test calculations using a database:

In the example above, you can see that I split the initialization of the repository and some calculations. Then I use a wrapper for mocking the repository to get a fake company and test calculations.

The use of static methods leads us to use functions as the main tool. For that purpose, C# has the powerful classes Func and Action and an incredible set of extensions - LINQ. The next section is all about them.

From loop to chain

As you already know, in order to represent a collection of data in C#, we have arrays, and the main tool for array processing is a loop. However, there are often many problems when using loops. First, in a loop, you get access to the array by an index and you should guess if your array has this index. Then you have to manually increase or decrease the index polluting the codebase with noise  which isn’t related to the business logic. Finally, every loop has a state - the current index and all your logic relies on it. That’s why I haven’t used loops for a long time.

C# has a much more convenient way to iterate a collection - the foreach statement. In this case, we don’t have indices and a state. Every iteration returns us a fresh item, so we can focus more on the business logic. Foreach is the best tool for processing every item in a collection.

Nevertheless, if you have filtering, checking, grouping or other complex calculations on the item, you will mess up the foreach statement body. Here, the more elegant solution would be to use LINQ. So instead of creating a huge set of method calls in the loop body, I suggest splitting all of your business logic into a set of small independent functions which transform the collection item on each step through the pipeline.

The Null Problem

As you probably are well aware, NullReferenceException is one of the most annoying errors that can crash your app. Tony Hoare, a scientist who developed the sorting algorithm quicksort, called null reference his billion-dollar mistake when he added this feature to the Algol programming language. In my opinion, using null reference should be manually defined like it has been done in F# and Kotlin. But while we are waiting for a new version of the language, we should implement all those checks by our own.

You can stumble across null references in the following places:

  • The method’s arguments
  • The method’s results
  • The object’s fields/properties.

There are several practices to check a method’s arguments for null. For example, using Code Contracts, ThrowIfNull or writing your own set of helpers and extensions. To avoid null references in method results, you can either control yourself to not return null anywhere in your code or, what is even better, use Code Contracts or ThrowIfNull on the other layer of method calls.

As you may have understood, this does not solve the problem, but only adds more unnecessary code. To eliminate nulls from your logic you have to go to a different level of abstraction. On this layer you can manually check and manage all specific cases, and handle all errors which could happen. In the next section, I will try to introduce you to such a pattern using a monad and several of its variations.

Monads to the Rescue

As I mentioned above, a monad encapsulates the values of a particular data type and creates a new type associated with a specific additional computation, typically to handle special cases of the type. A monad may have a default value for specific cases and two methods:

  • return - wrap a value into a monadic value.
  • bind - take a monadic value and a function which transforms the value.

Monads are very popular in pure functional languages, but in C# we often use them even without realizing it.

Let’s start from the most known monad in C# - List monad. In .NET, the List monad is represented as IEnumerable<T> - the core of LINQ. Every LINQ extension is a variation of the return method which somehow transforms the previous state and returns the monad which could be transformed again. To wrap the collection into the monad you can use AsEnumerable() method, or you can also define your own:

Then you can call them as a simple chain:

Working with IEnumerable, you don’t worry about null items or the length of the collection - you just know that every item in the collection will be transformed by your lambda function and in the worst case you’ll have an empty list.

The next monad I want to describe is the Maybe monad. This monad helps you check any reference for null in a more convenient way then I described above. Let’s first look at the example:

As you can see, both of these methods just check the input for null. The first function works on the level of abstraction and you can’t just get the value (it could be null) whereas the second function checks the input and if it’s null, returns a default value.

Since C# 6.0, we have a language feature which works in exactly the same way:

While developing your code, you may need a few more extensions:

And this example is quite straightforward:

The last monad I want to describe is the Try monad. TryXXX is a common pattern in .NET. When you want to parse or convert something, you write a construction like so:

Try monad has similar but more generic behavior. It keeps the value or thrown Exception and you can safely get the result without any runtime errors. Try has a bulky construction but I hope it’s easy to understand:

Extension Try just wraps the method call into a safe invocation. We can use TryResult without it, but in this situationwe should take care of exceptions ourselves. This could be useful if you want to handle various exceptions differently, rather than just packing them into TryResult. This example is also very straightforward and doesn’t need any explanations:

Conclusion

Now I would like to sum up all of the above. Functional programming is increasingly being introduced into real world applications. Nowadays, such technologies like IoT, serverless sites and other cloud based solutions push us to focus on the business logic rather than the code infrastructure. In this case, functional programming may be a more appropriate choice.

There is no full-fledged functional framework in .NET yet which allows you to write complete applications in a functional style. However, we can take advantage of both OOP and FP approaches and apply them side by side. I’m sure someone will come up with a new improved paradigm later, but for now let’s get the best from what we have.

  • Rambalac

    So, 1 page of code we replace “without boiler plate” to 2 pages of code? And for unittesting we need 4 pages of code? Instead of one simple and understandable class we get bunch of wrappers.
    Have you tried to make anything more complicated than Hello world or “functional” demo?
    Looks like you never tried multithreading, OOP has no relation to it. Just because you have option to make state shared between threads it does not mean you have to use it

    • luigimx

      I’ve tried more complicated things and my code is a lot better. OOP is state, dot, that’s way multithreading is, generally, hard in oop (for example, using locks).