Simple Functional Programming in C#

Some of the greatest crimes in modern computing are committed in the name of good object-orientated abstractions. Over time, a code base gets so polluted with abstract classes, factories and heavy dependencies on frameworks that a lot of it ends up serving as boilerplate to work around the rest. I’ve spent the last few months learning Haskell (A pure functional language) and Go (An imperative language that allows OO and functional styles) and it’s led me to the conclusion that John Carmack is right, sometimes all you really need is a function.

Go’s approach to OO struck me as very interesting because instead of complex class hierarchies they took a very simple approach and allowed you to associate a function with a type. There’s no this keyword, you assign the type a name and use that to access it’s properties. Here’s a very simple example:

Note: Unused variables are compile-time errors in Go, hence why this is much simpler than the upcoming C# examples.

We can do something similar in C#. Here’s a very simple OO example in C#. In pure OO, an object is a bundle of state and methods that operate on that state so I’m going with a contrived sample that demonstrates this.

Now lets look at the functional solution:

Note on line 2 we’ve given Tuples of type <string, string, int> the alias of Person. Since System.Tuple is a class, we create our Person tuple almost exactly the same way as our OO solution. The biggest difference is that there is no maintained state. Our CompareAge function takes two Person tuples and computes the required value. There’s also a lot less worrying about encapsulation, since we can explicitly see that our people tuples only exist in the scope where we create them.

I’ll expand on this post in the future with some more example of how aliasing types in C# can be used to write concise functional code. If you’d like to try this out, have a go at aliasing a list of Persons and writing a function that iterates over them and returns the total age of everyone (this is a classic example of a functional fold operation!)

I’m trying a more lean, agile approach to blogging because the tax on adding links and sources with my limited free time is too great and I don’t want to stop completely. If you want me to expand on anything in this post feel free to leave a comment or drop me a line and I’ll try my best.

Monads Demystified For Object-Orientated Programmers

I’d highly recommend checking out Douglas Crockford‘s keynote from YUIConf 2012 in which he details what exactly a monad is, and explains some of the fundamentals of functional programming, concurrency and asynchronous jobs along the way. You’ll find the talk embedded below.

Life Lessons Learned From Functional Programming

Functional programming languages such as Haskell, Scheme and Common Lisp have existed for years and provide all the tools needed to program in a manner that aims to eliminate side effects associated with procedural and object-orientated languages. This has the benefit of producing less code that is easier to maintain, and usually uses things like lazy evaluation to provide infinite lists and lambda anonymous functions unavailable in other languages.

However, compared to learning popular languages such as Java, C++ and Python functional languages are vastly different and much more difficult for beginners to grasp. Code written in a functional style is usually quite obfuscated to an outsider who has no notion of what functions like map, reduce and zip accomplish. In enterprise applications, where clarity of code is more often than not considered more important than how elegant the solution is, using a functional language is usually out of the question.

Despite this, I believe that doing things in a functional manner is not a bad thing at all, but more importantly, we can all learn something from the functional style. Here are some of the key properties of functional programming that if used correctly can make you a much better programmer regardless of what language you code in.

#1: Eliminate Side Effects

Side effects are any data that is determined at runtime and thus we cannot predict what it will do. The most common side effects are application state and I/O. Obviously both of these thing are used widely in nearly every single application used today and we can’t just go removing them. However, we should make a clear distinction in our functions about which ones produce side effects and which ones are considered pure.

Pure functions are those that do not suffer any side effects. Most of the time in a language like C or Java, we will not be able achieve true purity and somewhere along the chain of execution a side effect will be involved and thus all functions from there on will be transitively impure. By separating these functions into new ones, we will achieve easier error handling and data validation as a direct result.

#2: Pipelining functions

Pipelining function calls is probably something you’ve always done but not known the term for it. Consider the following Python code:

print inputPlus4(divideBy2((6+4) + (10)))
 >>> 14

By nesting our function calls, the return value of the first call becomes the input parameter for the second and so on. This may seem very simple but in reality it is very powerful. Wherever possible, all our functions should have a return type, and we should only use void when we absolutely must. Once a method is made void, we lose all the power that pipelining provides. Worse, it’s almost certain that by having lots of void functions in your code, lines of code will increase and more code means more maintenance. Pipelining used correctly also means less variables, and that’s another bonus for maintainability.

#3: Consider recursion

Now I’m not going to be purist here and say that recursion should be the only method of iteration you use in your code, but if it makes sense to use recursion then do it, even if it takes a little more time and ingenuity to do so. A classic practical example of recursion is calculating Fibonacci numbers. If you Google “Calculating Fibonacci numbers in X”, where X is you programming language of choice, you’ll find plenty of examples. The main advantage is that a recursive function can generally be proven mathematically correct more easily than if the function used a for or while loop.

I could give plenty more examples, such as the advantages of using lambda anonymous functions in Python, but I want to keep things language independent for now. I may follow up this post in the future with some examples of pure functional programming in Python, and even C# for the .NET enthusiasts out there.

To finish off, I’d like to reiterate over the main points of this post:

  • Keep code that deals with side effects separate from that which does not.
  • Aim to achieve function purity.
  • Functions should take input and return a value whenever possible. Void functions should be kept to the absolute minimum required by the solution.
  • Use recursion where it makes sense.