Functional Programming in C# by Enrico Buonanno

buonanno_hires

Title: Functional Programming in C# – How to write better C# code
Author: Enrico Buonanno
Published: 2017 by Manning
Pages: 408
My rating: 5/5
Goodreads.com rating: 4.78 (9 ratings)
Prerequisites: C# fundamentals
Whom I recommend: C# programmers who want to learn functional programming.

This was really interesting and educational book about functional programming (FP). What makes this book really good is that it is really practical.

My knowledge about FP was limited before I read this book. I had participated in an online course “Introduction to Functional Programming” by Eric Meijer in late 2015. But that was a quite theoretical course. Even if it included a lot of coding there wasn’t any bridge how you could practically use FP (maybe because I did only 2/3 of the course..). It was an interesting course, though.

This book included many practical examples which you can use in your everyday programming. For example, there were examples how to implement web API’s controller in FP way. And web APIs are what I do weekly in my work.

It was interesting to see how you can program functionally even with C#. Using C# restricts the audience of this book because you have to know fundamentals of C#, especially LINQ, to understand it. On the other hand, the book is really good for C# programmers. I think one key point why this was easier to understand than Eric Meijer’s course was that there was a familiar basis to begin: C#. You didn’t have to learn the language with this book. And another benefit was that it was made for object-oriented (OO) programmers. Buonanno compared things between OO and FP and it made the book easier to understand.

What I Learned About FP?

Now to some contents of the book. This part of the review is more self-teaching to me than a review. But I hope you can get something from it. You can read about “teaching to learn” from my first blog post.

Here are some interesting things I learned from this book which I will explain more:

  • Definition of pure function,
  • Power of static methods (ie. pure functions),
  • Option type,
  • Usage of Func delegate and
  • Immutable, append-only, database.

Definition of Pure Function

Requirements of pure functions
Requirements of pure functions (from the book).

The pure function is the key concept of FP. Think it like a function in mathematics: It takes arguments and returns value that is calculated only from arguments. It is a function that doesn’t have any side effects. Side effects are:

  • Mutates global state,
    • “Global” here means any state that’s visible outside of the function’s scope. For example, a private instance field is considered global because it’s visible from all methods within the class.
  • Mutates input argument(s),
  • Throws exception,
  • Performs any I/O operation.
    • This really means any I/O operation: read from or write to file, database or command prompt. Also using date/clock performs I/O operation.

For example following imaginary function isn’t pure because it has side effects:

public void AddName(List<string> names)
{
  Console.WriteLine("Enter a name: ");
  this.name = Console.ReadLine();
  if (string.IsNullOrEmpty(name)) throw new Exception("...");
  names.add(this.name);
}

As a matter of fact, Every line in the AddName function makes it impure because each line has a side effect. Lines 3 and 4 performs I/O operation by writing to console and reading input from the user/keyboard. In line 4 it mutates global state by changing the value of name field. In line 5 it may throw an exception. And lastly, in line 6 it mutates its input argument. (Note, that it is just an example of all possible side effects.)

The pure version of AddName function could be like this:

public static List<string> AddName(List<string> names, string nameToAdd)
{
  var copy = new List<string>(names);
  copy.add(nameToAdd);
  return copy;
}

This one doesn’t have any side effects:

  • It doesn’t mutate global state. For example, no instance field is mutated.
  • It doesn’t mutate arguments. It first copies names and mutates a copy, not the argument.
  • It doesn’t throw an exception.
  • It doesn’t perform any I/O action.

Practically, a pure function is a real static method. And these pure functions are the key point in FP. All lean on them, everywhere.

That doesn’t mean for example that there isn’t any I/O operation in FP programs. But in FP you will try to isolate I/O operations (and other side effects). For example in the previous example asking the name is isolated to AddName function’s caller.

About Not Throwing Exceptions

Throwing exception was mentioned as a side effect. This is something I don’t fully agree. I have to say I like exceptions and I think they are a powerful way to fail fast and fail with description. But here not throwing exceptions isn’t the whole truth. Error handling is just different in FP.

There is an Either type in C#. As a return type, it tells that function may return an error. I won’t explain it further here. It is like option type that I will explain later.

Power of Static Methods

In FP you will try to use pure functions as much as possible. Practically pure function means a static method in C#. But OO programmers have managed to avoid static methods. As an OO programmer, at first, I had big doubt about static methods (pure functions) reading this book. I have told many times to avoid static methods because unit testing is really difficult with them like Miško Hevery has said on his blog.

First, why OO programmers think static methods are bad? The main reason is that often they aren’t pure: many times they have side effects. Worst side effect they can have is an I/O operation. For example, if the static method is connecting to a database, it is impossible to avoid that I/O operation with a mock object. You are forced to connect to the database in your unit test.

But the more I read the book I realized that static methods without side effects can be quite good. There is a reason to implement pure functions. The main reason is that they are easy to test: just pass input and test output. Because there aren’t any side effects it is that simple (though creating inputs is difficult in some cases). Creating parameterized tests would be also easier for pure functions.

Pure functions are also safe to use because they don’t mutate arguments. You can call pure function and you are guaranteed that given argument, like a list or object, isn’t changed. It doesn’t have any side effects to the calling method so it is safe to use.

As an OO programmer I still rather prefer instance methods over static methods. But this book made me think about static methods in a new way. I won’t avoid them at any cost now, I even will use them. But they have to be pure. Probably I will write own blog post about static methods someday with this new information I gained from this book.

Option Type

Option is essentially a container that wraps a value…or no value. (Enrico Buonanno in this book)

Option is a type in FP (some call it “maybe”) that is practically like nullable type in C#. It either has a value or doesn’t have (like null). If we had an option type in C# it could be like:

Option<MyClass> myObject;  // "MyClass? myObject" as a nullable type

Compare it to following:

MyClass myObject;  // Is null allowed?

Using option type makes it clear that myObject is optional, it can have a value or it can be null. But with C# you can’t tell with reference types is it optional or not: can it be null or not.

I hadn’t thought much about how descriptive option type would be if we had it in C#. How many times have you been wondering “is null allowed or not?” or “can it return null?”. I haven’t many times, but just because I didn’t realize there could be a better way: option type. Yes, I have used nullable types in C# before, but somehow I didn’t think how usable they could be also with objects.

Ps. Option type is probably coming to C#: Introducing Nullable Reference Types in C#.

Usage of Func Delegate

Following image describes how important role functions have in FP and what you can do with them:

fpvsoo
OO patterns vs FP patterns (from Clean Code Blog).

First, this might sound bit funny but it is true: in FP there are functions everywhere.

In C# there is Func delegate which became familiar when reading the book. Before I didn’t fully understand for example what “`Func<string, int>“` meant. It means a function that takes a string as an argument and returns an int. There is also Action delegate which is a function that returns nothing (ie. void). You can see examples of how Func and Action can be represented as a lambda expression from the following picture:

Expressing function signatures with arrow notation
Func and Action types as lambda expression (from the book).

Practically I have used lambda expressions a lot for example with Moq (mocking NuGet) but before this, I didn’t realize how its signature should be read. But now I understand if there is “`Func<int, int, int>“` that what it means because there was a lot of Func delegate and lambda expressions in the book. Below is an example of using Func delegate:

public static int Calculate(Func<int, int, int> formula, Func<int> getA, Func<int> getB)
{
  var a = getA();
  var b = getB();
  return formula(a, b);
}

Here you pass a function to calculate as a formula argument. It has two int arguments (first two from <int, int, int>) and returns int (last from <int, int, int>). You even pass parameters to put to that formula as functions also (getA and getB). Those functions don’t get any arguments and they just return int. The last one in Func<x, y, z> is always the returning type (z). So if there is only one, like Func<x>, it means that x is the returning type. Here are two examples how to use Calculate function:

var getA = () => 100;
var getB = () => 44;
var multiply = (int a, int b) => a*b;
var result = Calculate(multiply, getA, getB);  // result=4400
var subtract = (int a, int b) => a-b;
result = Calculate(subtract, getA, getB);  // result=56

Even if I saw how you can use functions everywhere with Func delegate I have my doubt using it constantly. As an OO programmer using a function as an argument is not familiar to me. But maybe I will use it somewhere in my own code also little by little. But at least now I understand the code that uses Func or Action delegate.

Immutable, Append-Only, Database

If a function is number one keyword in FP, then immutability is probably number two. Around the book, it was emphasized that variables should be immutable. That is even quite confusing demand for OO programmer. But Buonanno showed that it is possible and even code’s readability won’t suffer from immutable variables. Though I guess readability will suffer if I, who is new to FP, try to write like that.

Then came quite a surprise for me: even database could be immutable! Well, practically not literally immutable but append-only. That means you use only inserts, not updates or deletes to the database. This was maybe most interesting part of the book (Chapter 10. Event sourcing: a functional approach to persistence).

The traditional functions of a relational DB are the CRUD operations: create, read, update, and delete. The functional approach to data storage is CRA: create, read, append. (Enrico Buonanno in this book)

The idea with an append-only database is that every time the data changes you just insert a new row into the table. And newest row for the item is item’s current state. This approach will serve history of data automatically; just go through data and you can receive item’s history.

After few thoughts append-only databases aren’t that bad. For example, with big data, you will receive a lot more data and its history when you don’t delete or overwrite data in the database.

In my opinion, an append-only database has two cons. You need more disk space and there will be more noise in your data. Disk space isn’t a big problem nowadays. With noise I mean when you go and look at your table, you will not be clear which rows are history and which are current state. And even by time, there will be more history than current states which will make it even more difficult to understand by human eyes. So debugging the data could be harder, especially if you are not interested in old data.

Conclusion

There has been a lot of talk about functional languages but so far I haven’t had interest in them. But this book opened my eyes what it is all about in FP. I think FP has really good things and it can make the code more readable and effective in some cases. As I mentioned in my Advent of Code blog post earlier.

FP isn’t easy to understand. You need to know some basics of it before you can understand it. It isn’t easy to understand how you can pass a function as an argument to other function. And when you see it, it is hard to understand what it is all about unless you are familiar with FP. So maybe better not to rush with functional code if you are using OO language like C#. But you can use some parts of functional way.

I predict that FP will continue growing its popularity. And developers who are coding with OO languages will take functional way as a part of their code. FP isn’t something new anymore, it is normal, even popular. Robert C. Martin said already 2012 in his blog that FP is the next big thing.

I deeply recommend this book to every C# developer. Now is the time to learn what functional programming is all about. But I warn you that this book will change your mind and the way you are thinking.

Functional programming is important. You should learn it. (Robert C. Martin in his blog)

Sources (other than reviewed book)

One thought on “Functional Programming in C# by Enrico Buonanno

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s