Book Image

Functional C#

Book Image

Functional C#

Overview of this book

Functional programming makes your application faster, improves performance, and increases your productivity. C# code is written at a higher level of abstraction, so that code will be closer to business requirements, abstracting away many low-level implementation details. This book bridges the language gap for C# developers by showing you how to create and consume functional constructs in C#. We also bridge the domain gap by showing how functional constructs can be applied in business scenarios. We’ll take you through lambda expressions and extension methods, and help you develop a deep understanding of the concepts and practices of LINQ and recursion in C#. By the end of the book, you will be able to write code using the best approach and will be able to perform unit testing in functional programming, changing how you write your applications and revolutionizing your projects.
Table of Contents (19 chapters)
Functional C#
Credits
About the Author
Acknowledgments
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Transforming imperative code to functional code


In this section, we will transform imperative code to functional code by leveraging method chaining. Suppose we want to create an HTML-ordered list containing the list of the planets in our solar system; the HTML will look as follows:

<ol id="thePlanets"> 
  <li>The Sun/li> 
  <li value="0">Mercury</li> 
  <li value="1">Venus</li> 
  <li value="2">Earth</li> 
  <li value="3">Mars</li> 
  <li value="4">Jupiter</li> 
  <li value="5">Saturn</li> 
  <li value="6">Uranus</li> 
  <li value="7">Neptune</li> 
</ol> 

The imperative code approach

We are going to list the name of planets, including the Sun. We will also mark the order of the planets with the value attribute in each li element. The preceding HTML code will be displayed in the console. We will create the list in ImperativeCode.csproj; here you go:

class Program 
{ 
  static void Main(string[] args) 
  { 
    byte[] buffer; 
    using (var stream = Utility.GeneratePlanetsStream()) 
    { 
      buffer = new byte[stream.Length]; 
      stream.Read(buffer, 0, (int)stream.Length); 
    } 
    var options = Encoding.UTF8 
      .GetString(buffer) 
      .Split(new[] { Environment.NewLine, }, 
             StringSplitOptions.RemoveEmptyEntries) 
      .Select((s, ix) => Tuple.Create(ix, s)) 
      .ToDictionary(k => k.Item1, v => v.Item2); 
    var orderedList = Utility.GenerateOrderedList( 
        options, "thePlanets", true); 
 
    Console.WriteLine(orderedList); 
  } 
} 

In the Main() method, we create a byte array, buffer, containing the planet stream we generate in other classes. The code snippet is as follows:

byte[] buffer; 
using (var stream = Utility.GeneratePlanetsStream()) 
{ 
  buffer = new byte[stream.Length]; 
  stream.Read(buffer, 0, (int)stream.Length); 
} 

We can see that there is a class named Utility, containing the GeneratePlanetStream() method. This method is used to generate the list of planets in the solar system in a stream format. Let's take a look at the following code in order to find what is inside the method:

public static partial class Utility 
{ 
  public static Stream GeneratePlanetsStream() 
  { 
    var planets = 
    String.Join( 
      Environment.NewLine, 
      new[] { 
        "Mercury", "Venus", "Earth", 
        "Mars", "Jupiter", "Saturn", 
        "Uranus", "Neptune" 
    }); 
 
    var buffer = Encoding.UTF8.GetBytes(planets); 
    var stream = new MemoryStream(); 
    stream.Write(buffer, 0, buffer.Length); 
    stream.Position = 0L; 
 
    return stream; 
  } 
} 

Firstly, it creates a variable named planets, containing eight planets named separately on a new line. We get the bytes of the ASCII using the GetBytes method, and then it is converted into a stream. This stream will be returned to the caller function.

In the main function, we also have variable options, as follows:

var options = Encoding.UTF8 
  .GetString(buffer) 
  .Split(new[] { Environment.NewLine, }, 
    StringSplitOptions.RemoveEmptyEntries) 
  .Select((s, ix) => Tuple.Create(ix, s)) 
  .ToDictionary(k => k.Item1, v => v.Item2); 

This will create a dictionary-typed variable, which contains the name of the planet and its order in the solar system. We use LINQ here, but we will discuss it deeper in the next chapter.

Then, we invoke the GenerateOrderedList() method inside the Utility class. This method is used to generate an HTML-ordered list containing the order of the planets in the solar system. The code snippet is as follows:

var orderedList = Utility.GenerateOrderedList( 
    options, "thePlanets", true);  

If we take a look at the GenerateOrderedList() method, we will find the following code:

public static partial class Utility 
{ 
  public static string GenerateOrderedList( 
    IDictionary<int, string> options, 
    string id, 
    bool includeSun) 
  { 
    var html = new StringBuilder(); 
    html.AppendFormat("<ol id="{0}">", id); 
    html.AppendLine(); 
 
    if (includeSun) 
    { 
      html.AppendLine("\t<li>The Sun/li>"); 
    } 
 
    foreach (var opt in options) 
    { 
      html.AppendFormat("\t<li value="{0}">{1}</li>",
      opt.Key,
      opt.Value); 
      html.AppendLine(); 
    } 
 
    html.AppendLine("</ol>"); 
 
    return html.ToString(); 
  } 
} 

First, in this method, we create a StringBuilder function named html and add an opening ol tag, which means an ordered list. The code snippet is as follows:

var html = new StringBuilder(); 
    html.AppendFormat("<ol id="{0}">", id); 
    html.AppendLine(); 

We also have Boolean variable, includeSun, to define whether we need to include Sun in the list. We get the value of this variable from the argument of the method. After that, we iterate the content of the dictionary we get from argument. This dictionary is generated by LINQ in the Main() method. We list the content by adding the li tag. The foreach keyword is used to achieve this goal. Here is the code snippet:

foreach (var opt in options) 
{ 
  html.AppendFormat("\t<li value="{0}">{1}</li>", 
    opt.Key, 
    opt.Value); 
  html.AppendLine(); 
} 

We can see that AppendFormat in the StringBuilder class is similar to String.Format, and we can pass Key and Value from dictionary. Do not forget to insert a new line for each li tag using the AppendLine method.

Lastly, we close the ol tag with the </ol> tag, which we define in the following snippet:

html.AppendLine("</ol>"); 

Then, we invoke the ToString() method to get a bunch of strings from StringBuilder. Now if we run the code, we will get the output on the console screen, as we discussed earlier.

The functional code approach

We have already developed imperative code in order to construct an HTML-ordered list of planet names, as discussed earlier. Now, from this imperative code, we are going to refactor it to functional code using method chaining. The functional code we build will be at FunctionalCode.csproj.

The GenerateOrderedList() method

We start with the GenerateOrderedList() method since we will modify its first three lines. It looks like the following in ImperativeCode.csproj:

var html = new StringBuilder(); 
  html.AppendFormat("<ol id="{0}">", id); 
  html.AppendLine(); 

We can refactor the preceding code to this:

var html = 
  new StringBuilder() 
    .AppendFormat("<ol id="{0}">", id) 
    .AppendLine(); 

The code becomes more natural now since it applies method chaining. However, we are still able to join the AppendFormat() method with the AppendLine() method in order to make it simple. To achieve this goal, we need help from method extension. We can create a method extension for StringBuilder as follows:

public static partial class StringBuilderExtension 
{ 
  public static StringBuilder AppendFormattedLine( 
    this StringBuilder @this,
    string format, 
    params object[] args) => 
       @this.AppendFormat(format, args).AppendLine(); 
} 

Now, because we have the AppendFormattedLine() method in the StringBuilder class, we can refactor our previous code snippet to the following:

var html = 
  new StringBuilder() 
      .AppendFormattedLine("<ol id="{0}">", id); 

The code snippet becomes much simpler than earlier. We also have the invocation of AppendFormat() following AppendLine() inside the foreach loop, as follows:

foreach (var opt in options) 
{ 
  html.AppendFormat("\t<li value="{0}">{1}</li>", 
    opt.Key, 
    opt.Value); 
  html.AppendLine(); 
} 

Therefore, we can also refactor the preceding code snippet using the AppendFormattedLine() function we added inside the StringBuilder class, as follows:

foreach (var opt in options) 
{ 
  html.AppendFormattedLine( 
    "\t<li value="{0}">{1}</li>", 
    opt.Key, 
    opt.Value); 
} 

Next, we have AppendLine() inside the conditional keyword if. We also need to refactor it to apply method chaining using the extension method. We can create the extension method for StringBuilder named AppendLineWhen(). The use of this method is to compare the condition we provide, and then it should decide whether or not it needs to be written. The extension method will be as follows:

public static partial class StringBuilderExtension 
{ 
  public static StringBuilder AppendLineWhen( 
    this StringBuilder @this, 
    Func<bool> predicate, 
    string value) => 
        predicate() 
         ? @this.AppendLine(value) 
          : @this;  
} 

Since we now have the AppendLineWhen() method, we can chain it to the previous code snippet, as follows:

var html = 
  new StringBuilder() 
    .AppendFormattedLine("<ol id="{0}">", id) 
    .AppendLineWhen(() => includeSun, "\t<li>The Sun/li>"); 

Thus, we are now confident about removing the following code from the GenerateOrderedList() method:

if (includeSun) 
{ 
  html.AppendLine("\t<li>The Sun/li>"); 
} 

We are also able to make the AppendLineWhen() method more general so that it not only accepts a string, but also takes a function as an argument. Let's modify the AppendLineWhen() method to the AppendWhen() method, as follows:

public static partial class StringBuilderExtension 
{ 
  public static StringBuilder AppendWhen( 
    this StringBuilder @this, 
    Func<bool> predicate, 
    Func<StringBuilder, StringBuilder> fn) => 
    predicate() 
    ? fn(@this) 
    : @this; 
} 

As we can see, the function now takes Func<StringBuilder, StringBuilder> fn as an argument to replace the string value. So, it now uses the function to decide the conditional with fn(@this). We can refactor var html again with our new method, as follows:

var html = 
  new StringBuilder() 
  .AppendFormattedLine("<ol id="{0}">", id) 
  .AppendWhen( 
    () => includeSun, 
    sb => sb.AppendLine("\t<li>The Sun/li>")); 

We have chained two methods so far; they are AppendFormattedLine() and AppendWhen() methods. The remaining function we have is foreach loop that we need to chain to the StringBuilder object named html. For this purpose, we create an extension method to a StringBuilder named AppendSequence() again, as follows:

public static partial class StringBuilderExtension 
{ 
  public static StringBuilder AppendSequence<T>( 
    this StringBuilder @this, 
    IEnumerable<T> sequence, 
    Func<StringBuilder, T, StringBuilder> fn) => 
      sequence.Aggregate(@this, fn); 
} 

We use the IEnumerable interface to make this function iterate over the sequence. It also invokes the Aggregate method in IEnumerable as an accumulator that counts the increasing sequence.

Now, using AppendSequence(), we can refactor the foreach loop and chain the methods to var html, as follows:

var html = 
  new StringBuilder() 
  .AppendFormattedLine("<ol id="{0}">", id) 
  .AppendWhen( 
    () => includeSun, 
    sb => sb.AppendLine("\t<li>The Sun/li>")) 
  .AppendSequence( 
    options, 
    (sb, opt) => 
      sb.AppendFormattedLine( 
      "\t<li value="{0}">{1}</li>", 
      opt.Key, 
      opt.Value)); 

The AppendSequence() method we add takes the options variable as the dictionary input and function of sb and opt. This method will iterate the dictionary content and then append the formatted string into StringBuilder sb. Now, the following foreach loop can be removed from the code:

foreach (var opt in options) 
{ 
  html.AppendFormattedLine( 
    "\t<li value="{0}">{1}</li>", 
    opt.Key, 
    opt.Value); 
} 

Next is the html.AppendLine("</ol>") function invocation we want to chain to the var html variable. This is quite simple because we just need to chain it without making many changes. Now let's take a look at a change in the var html assignment:

var html = 
  new StringBuilder() 
  .AppendFormattedLine("<ol id="{0}">", id) 
  .AppendWhen( 
    () => includeSun, 
    sb => sb.AppendLine("\t<li>The Sun/li>")) 
  .AppendSequence( 
    options, 
    (sb, opt) => 
      sb.AppendFormattedLine( 
        "\t<li value="{0}">{1}</li>", 
        opt.Key, 
        opt.Value)) 
  .AppendLine("</ol>"); 

As we can see in the preceding code, we refactor the AppendLine() method, so it is now chained to the StringBuilder declaration.

In the GenerateOrderedList() method, we have the following line of code:

return html.ToString(); 

We can also refactor the line so that it will be chained to the StringBuilder declaration in var html. If we chain it, we will have the following var html initialization:

var html = 
  new StringBuilder() 
  .AppendFormattedLine("<ol id="{0}">", id) 
  .AppendWhen( 
    () => includeSun, 
    sb => sb.AppendLine("\t<li>The Sun/li>")) 
  .AppendSequence( 
    options, 
    (sb, opt) => 
      sb.AppendFormattedLine( 
      "\t<li value="{0}">{1}</li>", 
      opt.Key, 
      opt.Value)) 
  .AppendLine("</ol>") 
  .ToString(); 

Unfortunately, if we compile the code now, it will yield the CS0161 error with the following explanation:

'Utility.GenerateOrderedList(IDictionary<int, string>, string, bool)': not all code paths return a value 

The error occurs because the method doesn't return any value when it's expected to return a string value. However, since it is functional programming, we can refactor this method in an expression member. The complete GenerateOrderedList() method will be as follows:

public static partial class Utility 
{ 
  public static string GenerateOrderedList( 
    IDictionary<int, string> options, 
    string id, 
    bool includeSun) => 
      new StringBuilder() 
      .AppendFormattedLine("<ol id="{0}">", id) 
      .AppendWhen( 
        () => includeSun, 
        sb => sb.AppendLine("\t<li>The Sun/li>")) 
      .AppendSequence( 
        options, 
        (sb, opt) => 
          sb.AppendFormattedLine( 
          "\t<li value="{0}">{1}</li>", 
          opt.Key, 
          opt.Value)) 
       .AppendLine("</ol>") 
       .ToString(); 
} 

We have removed the return keyword from the preceding code. We have also removed the html variable. We now have a function that has bodies as lambda-like expressions instead of statement blocks. This feature was announced in .NET Framework 4.6.

The Main() method

The Main() method in FunctionalCode.csproj is a typical method we usually face when programming in C#. The method flow is as follows: it reads data from the stream into the byte array and then converts those bytes into strings. After that, it performs a transformation to modify that string before passing it to the GenerateOrderedList() method.

If we look at the starting code lines, we get the following code snippet:

byte[] buffer; 
using (var stream = Utility.GeneratePlanetsStream()) 
{ 
    buffer = new byte[stream.Length]; 
    stream.Read(buffer, 0, (int)stream.Length); 
} 

We need to refactor the preceding code to be able to be chained. For this purpose, we create a new class named Disposable, containing the Using() method. The Using() method inside the Disposable class is as follows:

public static class Disposable 
{ 
  public static TResult Using<TDisposable, TResult> 
  ( 
    Func<TDisposable> factory, 
    Func<TDisposable, TResult> fn) 
    where TDisposable : IDisposable 
    { 
      using (var disposable = factory()) 
      { 
        return fn(disposable); 
      } 
    } 
}

In the preceding Using() method, we take two arguments: factory and fn. The function to which the IDisposable interface applies is factory, and fn is the function that will be executed after declaring the factory function. Now we can refactor the starting lines in the Main() method as follows:

var buffer = 
  Disposable 
  .Using( 
    Utility.GeneratePlanetsStream, 
    stream => 
    { 
      var buff = new byte[stream.Length]; 
      stream.Read(buff, 0, (int)stream.Length); 
      return buff; 
    }); 

Compared to imperative code, we have now refactored the code that reads the stream and stores it in a byte array with the help of the Dispose.Using() method. We ask the lambda stream function to return the buff content. Now, we have a buffer variable to be passed to the next phase, which is the UTF8.GetString(buffer) method. What we actually do in the GetString(buffer) method is transforming and then mapping the buffer to a string. In order to chain this method, we need to create the Map method extension. The method will look as follows:

public static partial class FunctionalExtensions 
{ 
  public static TResult Map<TSource, TResult>( 
    this TSource @this, 
    Func<TSource, TResult> fn) => 
    fn(@this); 
} 

Since we need to make it a general method, we use a generic type in the arguments of the method. We also use a generic type in the returning value so that it won't return only the string value. Using the generic types, this Map extension method will be able to transform any static type value into another static type value. We need to use an expression body member for this method, so we use the lambda expression here. Now we can use this Map method for the UTF8.GetString() method. The var buffer initialization will be as follows:

var buffer = 
  Disposable 
  .Using( 
    Utility.GeneratePlanetsStream, 
    stream => 
    { 
      var buff = new byte[stream.Length]; 
      stream.Read(buff, 0, (int)stream.Length); 
      return buff; 
    }) 
    .Map(Encoding.UTF8.GetString) 
    .Split(new[] { Environment.NewLine, }, 
    StringSplitOptions.RemoveEmptyEntries) 
  .Select((s, ix) => Tuple.Create(ix, s)) 
  .ToDictionary(k => k.Item1, v => v.Item2); 

By applying the Map method like the preceding code snippet, we don't need the following code anymore:

var options = 
  Encoding 
  .UTF8 
  .GetString(buffer) 
  .Split(new[] { Environment.NewLine, },  
    StringSplitOptions.RemoveEmptyEntries) 
  .Select((s, ix) => Tuple.Create(ix, s)) 
  .ToDictionary(k => k.Item1, v => v.Item2); 

However, the problem occurs since the next code needs variable options as arguments to the GenerateOrderedList() method, which we can see in following code snippet:

var orderedList = Utility.GenerateOrderedList( 
  options, "thePlanets", true); 

To solve this problem, we can use the Map methods as well to chain the GenerateOrderedList() method to the buffer variable initialization so that we can remove the orderedList variable. Now, the code will be look like what is shown in the following:

var buffer = 
  Disposable 
  .Using( 
    Utility.GeneratePlanetsStream, 
    stream => 
    { 
      var buff = new byte[stream.Length]; 
      stream.Read(buff, 0, (int)stream.Length); 
      return buff; 
    }) 
  .Map(Encoding.UTF8.GetString) 
  .Split(new[] { Environment.NewLine, }, 
    StringSplitOptions.RemoveEmptyEntries) 
  .Select((s, ix) => Tuple.Create(ix, s)) 
  .ToDictionary(k => k.Item1, v => v.Item2) 
  .Map(options => Utility.GenerateOrderedList( 
    options, "thePlanets", true)); 

Since the last line of code is the Console.WriteLine() method, which takes the orderedList variable as an argument, we can modify the buffer variable to orderedList. The change will be as follows:

var orderedList = 
  Disposable 
  .Using( 
    Utility.GeneratePlanetsStream, 
    stream => 
    { 
      var buff = new byte[stream.Length]; 
      stream.Read(buff, 0, (int)stream.Length); 
      return buff; 
    }) 
  .Map(Encoding.UTF8.GetString) 
  .Split(new[] { Environment.NewLine, }, 
    StringSplitOptions.RemoveEmptyEntries) 
  .Select((s, ix) => Tuple.Create(ix, s)) 
  .ToDictionary(k => k.Item1, v => v.Item2) 
  .Map(options => Utility.GenerateOrderedList( 
    options, "thePlanets", true));  

The last line in the GenerateOrderedList() method is the Console.WriteLine() method. We will also chain this method to the orderedList variable. For this purpose, we need to extend a method called Tee, containing the pipelining technique we discussed earlier. Let's take a look at the following Tee method extension:

public static partial class FunctionalExtensions 
{ 
  public static T Tee<T>( 
    this T @this,  
    Action<T> action) 
  { 
    action(@this); 
    return @this; 
  } 
} 

From the preceding code, we can see that the output of Tee will be passed to the input of the Action function. Then, we can chain the last line using Tee, as follows:

Disposable 
  .Using( 
    Utility.GeneratePlanetsStream, 
    stream => 
    { 
      var buff = new byte[stream.Length]; 
      stream.Read(buff, 0, (int)stream.Length); 
      return buff; 
    }) 
  .Map(Encoding.UTF8.GetString) 
  .Split(new[] { Environment.NewLine, }, 
    StringSplitOptions.RemoveEmptyEntries) 
  .Select((s, ix) => Tuple.Create(ix, s)) 
  .ToDictionary(k => k.Item1, v => v.Item2) 
  .Map(options => Utility.GenerateOrderedList( 
    options, "thePlanets", true)) 
  .Tee(Console.WriteLine); 

Tee can return the HTML generated by the GenerateOrderedList() method so that we can remove the orderedList variable from the code.

We can also implement the Tee method to the lambda expression in the preceding code. We will refactor the following code snippet using Tee:

stream => 
{ 
  var buff = new byte[stream.Length]; 
  stream.Read(buff, 0, (int)stream.Length); 
  return buff; 
} 

Let's understand what the preceding code snippet is actually doing. First, we initialize the byte array variable buff to store as many bytes as the length of the stream. It then populates this byte array using the stream.Read method before returning the byte array. We can also ask the Tee method to do this job. The code will be as follows:

Disposable 
  .Using( 
    Utility.GeneratePlanetsStream, 
    stream => new byte[stream.Length] 
  .Tee(b => stream.Read( 
    b, 0, (int)stream.Length))) 
  .Map(Encoding.UTF8.GetString) 
  .Split(new[] { Environment.NewLine, }, 
    StringSplitOptions.RemoveEmptyEntries) 
  .Select((s, ix) => Tuple.Create(ix, s)) 
  .ToDictionary(k => k.Item1, v => v.Item2) 
  .Map(options => Utility.GenerateOrderedList( 
    options, "thePlanets", true)) 
  .Tee(Console.WriteLine);  

Now, we have a new Main() method, applying method chaining to approach functional programming.