Cook Computing

Linq and Functional Programming

June 27, 2009 Written by Charles Cook

I'm writing some code to display some old blog posts and after retrieving each post as a single string containing CR-LF separated lines I needed to split the string into individual lines and wrap each line with a <p> tag. I could split the string using String.Split but I wondered if it was possible to use a StringReader to generate an enumeration of the lines in the string. It turns out that StringReader doesn't support this but I wrote an extension method to supply the required functionality:


public static partial class Extensions
{
  public static IEnumerable<string> Lines(this TextReader textReader)
  {
    string line;
    while ((line = textReader.ReadLine()) != null)
      yield return line;
  }
}

The extension method is defined for the TextReader parent class of StringReader so it will also work for StreamReader, which makes it possible, for example, to generate an enumeration of the lines in a file (you could use File.ReadAllLines but that generates the array of every line in the file when it is called, whereas using an iterator means that data is read from the file as required for each yield statement).

I also needed to concatenate the strings in the sequence of lines so I wrote another extension method:


public static partial class Extensions
{
  public static string Concatenate(this IEnumerable<string> strings,
    string separator)
  {
    StringBuilder strbldr = new StringBuilder();
    foreach (string str in strings)
    {
      if (strbldr.Length > 0)
        strbldr.Append(separator);
      strbldr.Append(str);
    }
    return strbldr.ToString();
  }
}

This then allows me to write code like this:


string txt = @"one
two
three";
StringReader rdr = new StringReader(txt);
string output = rdr.Lines()
  .Where(line => line != "")
  .Select(line => "<p>" + line + "</p>")
  .Concatenate(Environment.NewLine);

I am finding that with the influence of Linq I am using a more functional style of coding, not just for manipulating data in a database but also for in-memory objects such as arrays. Treating an array as a sequence to which you can apply functions to means you can write higher level code which is easier to understand, and which is less likely to have bugs, because the code is focused on the required functionality rather than how to implement it.

Bill Venners in How Scala Changed My Programming Style describes a similar experience. His example translates to C# as follows: the imperative version:


var nameHasUpperCase = false; 
for (int i = 0; i < name.Length; i++)
{
  if (char.IsUpper(name[i]))
  {
    nameHasUpperCase = true;
    break;
  }
}

And the functional version:


var nameHasUpperCase = name.Any(c => char.IsUpper(c));

Of course, as Raganwald says in Why Why Functional Programming Matters Matters, speaking of how functional code expresses a lot more what and a lot less how, this doesn't come for free:

In general, we think this is a good thing. But it isn't free: somewhere else there is a mass of code that supports your brevity. When that extra mass of code is built into the programming language, or is baked into the standard libraries, it is nearly free and obviously a Very Good Thing. A language that doesn't just separate the concern of how but does the work for you is very close to "something for nothing" in programming.

In the case of the code above I had to write the extension methods but in a more functionally oriented language it might not be necessary to write anything extra.

In general, I wonder if a language designed to be inherently more functional, such as F#, is worth learning; not necessarily as a language for day-to-day use —it may be sometime before it achieves widespread commercial usage, if ever — but because it might feed back into using C# more effectively, moving towards a more functional style of coding where possible.