/.NET /C# /Functional Programming /monads

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:

public class Service { public Service(ISessionFactory sessionFactory, IUserRepository userRepository, ICompanyRepository companyRepository, IHttpClient httpClient, /* few more dependencies */ IEmailService emailService) { // init dependencies } public IList<User> GetUsers() { using (var session = sessionFactory.Create()) return userRepository.GetUsers(); } public Company GetUserCompany(long userId) { using (var session = sessionFactory.Create()) companyRepository.GetCompanyByUser(userId); } /* other methods */ } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Service { public Service ( ISessionFactory sessionFactory , IUserRepository userRepository , ICompanyRepository companyRepository , IHttpClient httpClient , /* few more dependencies */ IEmailService emailService ) { // init dependencies } public IList < User > GetUsers ( ) { using ( var session = sessionFactory . Create ( ) ) return userRepository . GetUsers ( ) ; } public Company GetUserCompany ( long userId ) { using ( var session = sessionFactory . Create ( ) ) companyRepository . GetCompanyByUser ( userId ) ; } /* other methods */ }

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.

public class Service { public Service (IPdfBuilder builder) { this.builder = builder; this.builder.Init(PdfType.User); } public byte[] GeneratePdf(List<User> users) { this.builder.AddHeader(); foreach(var user in users) { this.builder.AddRow(user.ToFormatString()); this.builder.AddLine(); } this.builder.AddFooter(); return this.builder.GetData(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Service { public Service ( IPdfBuilder builder ) { this . builder = builder ; this . builder . Init ( PdfType . User ) ; } public byte [ ] GeneratePdf ( List < User > users ) { this . builder . AddHeader ( ) ; foreach ( var user in users ) { this . builder . AddRow ( user . ToFormatString ( ) ) ; this . builder . AddLine ( ) ; } this . builder . AddFooter ( ) ; return this . builder . GetData ( ) ; } }

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:

public class Service { public Service( /* I removed dependencies which we no longer need */ IHttpClient httpClient, /* few more dependencies */ IEmailService emailService) { // init dependencies } public IList<User> GetUsers() => LoadUsers(); public Company GetUserCompany(long userId) => LoadUserCompany(userId); private static IList<User> LoadUsers() { using (var repo = RepositoryFactory.CreateUserRepository()) return repo.GetUsers(); } private static Company LoadUserCompany(long userId) { using (var repo = RepositoryFactory.CreateCompanyRepository()) return repo.GetCompanyByUser(userId); } /* other methods */ } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Service { public Service ( /* I removed dependencies which we no longer need */ IHttpClient httpClient , /* few more dependencies */ IEmailService emailService ) { // init dependencies } public IList < User > GetUsers ( ) = > LoadUsers ( ) ; public Company GetUserCompany ( long userId ) = > LoadUserCompany ( userId ) ; private static IList < User > LoadUsers ( ) { using ( var repo = RepositoryFactory . CreateUserRepository ( ) ) return repo . GetUsers ( ) ; } private static Company LoadUserCompany ( long userId ) { using ( var repo = RepositoryFactory . CreateCompanyRepository ( ) ) return repo . GetCompanyByUser ( userId ) ; } /* other methods */ }

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

public static class Service { private static IList<User> GetUsers() { using (var repo = RepositoryFactory.CreateUserRepository()) return repo.GetUsers(); } private static Company GetUserCompany(long userId) { using (var repo = RepositoryFactory.CreateCompanyRepository()) return repo.GetCompanyByUser(userId); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 public static class Service { private static IList < User > GetUsers ( ) { using ( var repo = RepositoryFactory . CreateUserRepository ( ) ) return repo . GetUsers ( ) ; } private static Company GetUserCompany ( long userId ) { using ( var repo = RepositoryFactory . CreateCompanyRepository ( ) ) return repo . GetCompanyByUser ( userId ) ; } }

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:

public class Service { public static decimal GetCompanyBudget(long id) { using(var repo = RepositoryFactory.CreateRepository()) return CalculateBudget(repo, id); } // Notice that I use protected method to call it from wrapper protected static decimal CalculateBudget(CompanyRepository repo, long id) { var company = repo.Get(id); var budget = 0; // calculate budget return budget; } } public class Wrapper : Service { public static WrapCalculation(CompanyRepository repo, long id) => CalculateBudget(repo, id); // use fake repository for unit testing } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Service { public static decimal GetCompanyBudget ( long id ) { using ( var repo = RepositoryFactory . CreateRepository ( ) ) return CalculateBudget ( repo , id ) ; } // Notice that I use protected method to call it from wrapper protected static decimal CalculateBudget ( CompanyRepository repo , long id ) { var company = repo . Get ( id ) ; var budget = 0 ; // calculate budget return budget ; } } public class Wrapper : Service { public static WrapCalculation ( CompanyRepository repo , long id ) = > CalculateBudget ( repo , id ) ; // use fake repository for unit testing }

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.

foreach (var company in companies) PrintCompanyInfo(company); 1 2 foreach ( var company in companies ) PrintCompanyInfo ( company ) ;

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.

companies .Where(FilterCompanies) .SelectMany(SelectUsers) .Select(CalculateUserFee); 1 2 3 4 companies . Where ( FilterCompanies ) . SelectMany ( SelectUsers ) . Select ( CalculateUserFee ) ;

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:

public static IEnumerable<TInput> ToList<TInput>(TInput o) { yield return o; } public static IEnumerable<U> MySelectMany<T, U>(this IEnumerable<T> m, Func<T, IEnumerable<U>> k) { foreach (var x in m) foreach (var y in k(x)) yield return y; } 1 2 3 4 5 6 7 8 9 10 11 public static IEnumerable < TInput > ToList < TInput > ( TInput o ) { yield return o ; } public static IEnumerable < U > MySelectMany < T , U > ( this IEnumerable < T > m , Func < T , IEnumerable < U > > k ) { foreach ( var x in m ) foreach ( var y in k ( x ) ) yield return y ; }

Then you can call them as a simple chain:

var result = array .MySelectMany(x => array2 .MySelectMany(y => ToList(x + y))) .ToList(); 1 2 3 4 var result = array . MySelectMany ( x = > array2 . MySelectMany ( y = > ToList ( x + y ) ) ) . ToList ( ) ;

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:

public static TResult With<TInput, TResult> (this TInput o, Func<TInput, TResult> evaluator) where TInput : class where TResult : class { if (o == null) return null; return evaluator(o); } public static TResult Return<TInput, TResult> (this TInput o, Func<TInput, TResult> evaluator, TResult failueValue) where TInput : class where TResult : class { if (o == null) return failueValue; return evaluator(o); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static TResult With < TInput , TResult > ( this TInput o , Func < TInput , TResult > evaluator ) where TInput : class where TResult : class { if ( o == null ) return null ; return evaluator ( o ) ; } public static TResult Return < TInput , TResult > ( this TInput o , Func < TInput , TResult > evaluator , TResult failueValue ) where TInput : class where TResult : class { if ( o == null ) return failueValue ; return evaluator ( o ) ; }

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.

user .With(x => x.Info) .With(x => x.FullName) .Return(x => x.FirstName, string.Empty); 1 2 3 4 user . With ( x = > x . Info ) . With ( x = > x . FullName ) . Return ( x = > x . FirstName , string . Empty ) ;

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

user?.Info?.FullName?.FirstName ?? string.Empty; 1 user ? . Info ? . FullName ? . FirstName ? ? string . Empty ;

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

public static TInput If<TInput> (this TInput o, Predicate<TInput> evaluator) where TInput : class { if (o == null) return null; return evaluator(o) ? o : null; } public static TInput Do<TInput> (this TInput o, Action<TInput> action) where TInput : class { if (o == null) return null; action(o); return o; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static TInput If < TInput > ( this TInput o , Predicate < TInput > evaluator ) where TInput : class { if ( o == null ) return null ; return evaluator ( o ) ? o : null ; } public static TInput Do < TInput > ( this TInput o , Action < TInput > action ) where TInput : class { if ( o == null ) return null ; action ( o ) ; return o ; }

And this example is quite straightforward:

User .With(x => x.Info) .With(x => x.FullName) .With(x => x.FirstName) .If(x => x.Length > 4) .Do(Console.WriteLine); 1 2 3 4 5 6 User . With ( x = > x . Info ) . With ( x = > x . FullName ) . With ( x = > x . FirstName ) . If ( x = > x . Length > 4 ) . Do ( Console . WriteLine ) ;

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:

int result = 0; if (int.TryParse("10", out result)) { // Do something } 1 2 3 4 5 int result = 0 ; if ( int . TryParse ( "10" , out result ) ) { // Do something }

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:

// Delegate which will contain our logic public delegate TryResult<T> Try<T>(); // Simple structure that keeps value or exception public struct TryResult<T> { public readonly T Value; public readonly Exception Exception; public TryResult(T value) { Value = value; Exception = null; } public TryResult(Exception e) { Exception = e ?? throw new ArgumentNullException("e"); Value = default(T); } // Wrap any value into our monad public static implicit operator TryResult<T> (T value) => new TryResult<T>(value); public bool IsFaulted => Exception != null; } public static class TryExt { // Safe invoke of our logic public static TryResult<T> Try<T>(this Try<T> self) { try { return self(); } // If something happens, wrap the exception catch (Exception e) { return new TryResult<T>(e); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 // Delegate which will contain our logic public delegate TryResult < T > Try < T > ( ) ; // Simple structure that keeps value or exception public struct TryResult < T > { public readonly T Value ; public readonly Exception Exception ; public TryResult ( T value ) { Value = value ; Exception = null ; } public TryResult ( Exception e ) { Exception = e ? ? throw new ArgumentNullException ( "e" ) ; Value = default ( T ) ; } // Wrap any value into our monad public static implicit operator TryResult < T > ( T value ) = > new TryResult < T > ( value ) ; public bool IsFaulted = > Exception ! = null ; } public static class TryExt { // Safe invoke of our logic public static TryResult < T > Try < T > ( this Try < T > self ) { try { return self ( ) ; } // If something happens, wrap the exception catch ( Exception e ) { return new TryResult < T > ( e ) ; } } }

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:

public static void Try() { ShowResult(DoSomething(10).Try()); ShowResult(DoSomethingError(10).Try()); } // Wrap the logic into Try delegate private static Try<int> DoSomething(int value) => () => value + 1; private static Try<int> DoSomethingError(int value) => () => throw new Exception("Whoops"); // Test the result of monad private static void ShowResult<T>(TryResult<T> monad) => Console.WriteLine(monad.IsFaulted ? monad.Exception.Message : monad.Value.ToString()); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void Try ( ) { ShowResult ( DoSomething ( 10 ) . Try ( ) ) ; ShowResult ( DoSomethingError ( 10 ) . Try ( ) ) ; } // Wrap the logic into Try delegate private static Try < int > DoSomething ( int value ) = > ( ) = > value + 1 ; private static Try < int > DoSomethingError ( int value ) = > ( ) = > throw new Exception ( "Whoops" ) ; // Test the result of monad private static void ShowResult < T > ( TryResult < T > monad ) = > Console . WriteLine ( monad . IsFaulted ? monad . Exception . Message : monad . Value . ToString ( ) ) ;

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.