Real World Functional Style Programming Patterns in C#

BY Matthew Lovelady

There are a considerable number of people who will gush over functional programming, and I am one of those people. The use of mathematical functions to determine computational output based only on the arguments that are input to the function is a sweet, organized melody of calculated logic to my inner soul.

Sadly, C# is not a true functional language. However, it is becoming more and more like one as C# methods are “first class citizens.” In other words, you can pass a method just as you can pass an int, float, string, or any other data type.

In this post, we are going to look at a real world example where a C# functional pattern can be used to control a simple slideshow application. We frequently create such slideshows for product-based interactives at a trade show or touchscreen exhibits for collections at libraries or museums.

Let’s consider three different collections and approaches for displaying a slideshow of images. The difference between these collections will be how we handle navigation looping. What I mean by navigation looping will become obvious during the course of this example.

  • Collection 1 is a set of date-ordered artifacts for an interactive timeline application. In a timeline scenario, you have absolute navigation bounds. When you come to the end of the timeline, we don’t want to loop from the end date back to the beginning date. The user expects to navigate the dates in a linear, chronological order.
  • Collection 2 is a set of book covers. Users are very familiar with navigating books in a looping, carousel-style navigation. In other words, each time you come to the last book cover in the collection, the application will automatically loop back to the starting book as if all the books were placed on a carousel.
  • Collection 3 is a set of product images. Like Collection 2, we are going to display these products in an looping carousel. However, the manufacturer wants a more playful experience, so we are going to use gesture-based input to control how quickly the carousel spins. In this scenario, the force of the gesture input will not only loop the collection, but it will also determine for far into the collection the carousel will progress.

Let’s see if we can code a functional style solution in C# to meet all three of these requirements.


public class MCollection : IEnumerable
{
int Ndx = 0;
readonly List Coll = new List();
readonly Func StepboundsF;

public MCollection(Func stepboundsFunc)
{
StepboundsF = stepboundsFunc;
}

...
...
public MCollection Add(IEnumerable data)
{
Coll.AddRange(data);
return this;
};

public T this[int ndx] => Coll[StepboundsF(ndx,0,Count -1)];

private T Step(int stride) => Coll[Ndx = StepboundsF(Ndx + stride, 0, Coll.Count - 1)];

public T Previous => Step(-1);

public T Next => Step(1);

public T Current => Coll[Ndx];

public int CurrentIndex => Ndx;

...
...
}

The code above establishes the foundation for processing any of our collections. Now, let’s see how we can use C# functions to meet the user experience requirements for each type of collection.


Func Clamp = (n, min, max) => n < min ? min : n > max ? max : n;
Func Loop = (n,min,max) => n < min ? max : n > max ? min : n;

Func LoopMod = (n, min, max) => (n < min || n > max) ? n % max : n;

var data = Enumerable.Range(0, 8);
var collClamp = new MCollection(Clamp).Add(data);
var collLoop = new MCollection(Loop).Add(data);
var collModLoop = new MCollection(LoopMod).Add(data);

var colls = new[] { collClamp, collLoop, collModLoop };

foreach (var i in Enumerable.Range(0,9))
{
foreach (var coll in colls)
{
coll.Step(2);
}
WriteLine($"CollClamps index : {collClamp.CurrentIndex} ,
collLoop index : {collLoop.CurrentIndex} ,
collModLoop index : {collModLoop.CurrentIndex}");
}

Running the above produces the output below.

CollClamps index : 2 , collLoop index : 2 , collModLoop index : 2
CollClamps index : 4 , collLoop index : 4 , collModLoop index : 4
CollClamps index : 6 , collLoop index : 6 , collModLoop index : 6
CollClamps index : 7 , collLoop index : 0 , collModLoop index : 1
CollClamps index : 7 , collLoop index : 2 , collModLoop index : 3
CollClamps index : 7 , collLoop index : 4 , collModLoop index : 5
CollClamps index : 7 , collLoop index : 6 , collModLoop index : 7
CollClamps index : 7 , collLoop index : 0 , collModLoop index : 2
CollClamps index : 7 , collLoop index : 2 , collModLoop index : 4
CollClamps index : 7 , collLoop index : 4 , collModLoop index : 6

Therefore, we just met all of our requirements for our collections with a single code base. All we had to do was inject a method that behaved the way we wanted.

  • Collection 1 (the timeline of artifacts): We could use our MCollection class and simply pass it the Clamp method. This method will create a definite beginning and end to our set of ordered dates.
  • Collection 2 (the book carousel): We simply inject the Loop method instead of Clamp with no other changes needed to create an infinite slideshow or carousel of book covers.
  • Collection 3 (the gesture-based product spinner): We use the LoopMod method to not only loop the images, but also to step forward a specified number.

As a comparison between the functional programming approach above and the object oriented approach, the latter would dictate the following scenarios:

  • We could create an interface for our collection, and then make a looping collection plus a non-looping collection.
  • We could create IsLooping as a property.
  • We could employ the dreaded inheritance method as a last resort.
  • (And, yes, there are some other options that progress along similar lines as the above, but we won’t take time to list every possible option here.)

All of the object oriented solutions listed above have some fairly significant issues. Maintaining two implementations of an interface for our requirements seems unreasonable to me–and I am a guy who loves interfaces. Adding an IsLooping property to our class introduces a bit of unnecessary complexity in the form of several code branches, so that’s no good. And then there is Inheritance…well let’s just move on and look for another option. In my experience, Inheritance confuses, complicates, and limits things.

Maybe we could make an IStepBounds interface and pass implementations. At least this solution is more object oriented. However, we don’t need to make an interface and all of its implementations. Our method signature is the interface and our method is the implementation, so why create extra classes and interfaces?

We can improve our design by making a nice mix of OOP and functional style programming. The die hard object oriented programmers would assert that another solution is to move the navigation behaviour to a higher level of abstraction, something along the lines of…

Navigator>(Func boundsF)

The code snippet above would achieve the same thing as our MCollection did. The benefit of this code is that we move the state of navigation to the Navigator class, and taking advantage of the already existing collections is .Net. I prefer this style of design because of the separation of concerns and locality of state, but it is not as demo friendly in my humble opinion.

All in all, I believe there are more benefits to thinking and implementing code in a functional way versus the object oriented method. Although we covered only a tiny portion of functional thought, I hope this post gets you thinking about functional approaches in C#. Perhaps in a future post we will continue the functional theme and look at LINQ to explore how we can add query expressions.

Scroll Up
 Previous  All works Next