New C# 9 features and their F# counterparts

I recently watched Mads Torgersen’s video presentation of C# 9 from Microsoft Build and also read his presentation on the same topic titled Welcome to C# 9.0. It is obvious that the C# team is heavily inspired by functional programming and many of the new features have equivalents in F# (where they have existed for a long time). I thought it would be interesting to do a comparison of the new features and their F# counterparts. Since C# is primarily an object oriented language it might be difficult to add functional concepts in a way that fits well into the existing language. Let’s see what it looks like.

Init-only properties

Several of the new C# 9 features focuses on immutability. For those of you familiar with functional programming it is no news that immutability is one of the ground pillars of the functional paradigm. Mutating data is something we associate with imperative and object oriented programming.

C# 9 will introduce a feature called init-only properties which limits the possibility to set property values to only when a new instance of an object is created. Let’s look at some code.

// Prior to C# 9
public class Person 
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
}
var person = new Person { FirstName = "Eric", LastName = "Backhage" };
// It is possible to change the value of the properties whenever, this
// might not be something you want.
person.FirstName = "Carl";

// With C# 9
public class Person
{
  // Notice that 'set' has been changed to 'init'
  public string FirstName { get; init; }
  public string LastName { get; init; }
}
var person = new Person { FirstName = "Eric", LastName = "Backhage" };
// With 'set' changed to 'init' the following line will not compile.
person.FirstName = "Carl";
// However, it is still possible to set the 'person' variable to
// a different value.
person = new Person { FirstName = "Carl", LastName = "Backhage" }; 

F# – Record type assigned to mutable variable

If I wanted to have similar behavior in F# I would use a record type and assign it to a variable that is declared as mutable. The code would look like this:

type Person = { FirstName: string; LastName: string }
let mutable person = { FirstName = "Eric"; LastName = "Backhage" }
// As in the C# version the following line would not compile
person.FirstName <- "Carl"
// But it is still possible to set the 'person' variable to a
// different value
person <- { FirstName = "Carl"; LastName = "Backhage" }

The only reason I would use ’mutable’ however is for variables that are updated thousands of times in a tight loop. In other cases I would use the default behavior of immutable variables. We’ll see this next.

Records

Records in C# has been planned for a long time and it feels really nice that they finally seem to make it into the language. For those of you unfamiliar with Records they can be described as immutable data containers without any logic (methods) associated with them. To define a Record type in C# 9 you add the keyword data to the class definition. Like this:

public data class Person
{
  public string FirstName { get; init; }
  public string LastName { get; init; }
}
/* 
  There is also a shorthand that removes most of the 
   boiler plate. The above code can be written like
   this instead:
   public data class Person { string FirstName; string LastName }
*/
// Creating an instance of Person is no different
// than before
var person = new Person { FirstName = "Eric", LastName = "Backhage" };
// Properties are still init-only so the following line
// will not compile
person.FirstName = "Carl";
// However, since Person is now a Record the
// following line will also not compile
person = new Person { FirstName = "Carl", LastName = "Backhage" };
// Instead you must introduce a new variable
var anotherPerson = person with { FirstName = "Carl" };
// The 'with' keyword lets you clone properties from another
// instance. anotherPerson.LastName is equal to "Backhage"

F# – Records

In F# Records is one of the core language types and has been around forever. The above C# 9 code looks like this in F#:

type Person = { FirstName: string; LastName: string }
let person = { FirstName = "Eric"; LastName = "Backhage" }
// As in C# 9 the following does not compile
person.FirstName <- "Carl"
person <- { FirstName = "Carl"; LastName = "Backhage" }
// Instead you need to introduce a new variable
let anotherPerson = { person with FirstName = "Carl" }

C# 9 Records – value based equality

Unlike regular classes, that uses reference based equality unless you override the Equals method, C# 9 Records will use value based equality. That means that if two records are of the same type and their properties have the same values, they will be considered equal. Let’s look at some example code.

public data class Person { string FirstName; string LastName; }
var p1 = new Person { FirstName = "Eric", LastName = "Backhage" };
var p2 = new Person { FirstName = "Eric", LastName = "Backhage" };
var p3 = new Person { FirstName = "Carl", LastName = "Karlsson" };

p1.Equals(p2); // => true
p2.Equals(p3); // => false

In F#, Records works exactly in the same way, you just use ’=’ for equality checking instead:

type Person { FirstName: string; LastName: string }
let p1 = { FirstName = "Eric"; LastName = "Backhage" }
let p2 = { FirstName = "Eric"; LastName = "Backhage" }
let p3 = { FirstName = "Carl"; LastName = "Karlsson" }

p1 = p2 // -> true
p2 = p3 // -> false

C# 9 Records – Positional Records

Positional Records is a nice shorthand that reduces the amount of boiler plate code needed when defining record types with constructors and deconstructors. The code example below shows how it will work.

public data class Person(string FirstName, string LastName);

/* The code above is actually equal to all of this:
public data class Person
{
  string FirstName;
  string LastName;
  public Person(string firstName, string lastName)
    => (FirstName, LastName) = (firstName, lastName);
  public void Deconstruct(out string firstName, out string lastName)
    => (firstName, lastName) = (FirstName, LastName);
}
*/
// Instantiating
var person = new Person("Eric", "Backhage");
// Deconstructing
var (firstName, lastName) = person;

Now we are getting on par with F# in terms of being succinct. Let’s compare the same operations line by line:

// C# 9
public data class Person(string FirstName, string LastName);
// F#
type Person { FirstName: string; LastName: string }
// C# 9
var person = new Person("Eric", "Backhage");
// F#
let person = { FirstName = "Eric"; LastName = "Backhage" };
// C# 9
var (firstName, lastName) = person;
// F#
let { FirstName = firstName; LastName = lastName } = person

Nice work of the C# team!

C# 9 Records – Inheritance

True to the object oriented paradigm, C# Records will support inheritance. You will be able to create base Records and create derivatives that inherit from them. It will look like this:

public data class Person { string FirstName; string LastName; }
public data class Student : Person { int ID; }

var student = new Student { FirstName = "Eric", LastName = "Backhage", ID = 1 };

Since inheritance is an object oriented concept and F# is a functional-first language F# Records can not be inherited. The solution is to use composition instead. One way of accomplishing similar behavior in F# is shown in the code below:

type PersonalInfo = { FirstName: string; LastName: string }
type Student = { ID: int; PersonalInfo: PersonalInfo }

let student = { ID = 1; PersonalInfo = { FirstName = "Eric"; LastName = "Backhage" } }

My personal preference here is composition. I believe that the C# team have had a really tough time getting value based equality and instantiation using the ’with’ keyword working well with inheritance, hope it will be worth it.

Conclusion and further reading

I think the new C# 9 features will be great additions to the C# language and it is my opinion that the C# language design team are doing a great job adding nice new features to the language. Immutable records are not something you would normally expect to find in an object oriented language, and they feel a lot more natural in F#, but I am confident they will make a great addition to C# now that they are finally coming.

For more information on upcoming C# 9 features that I haven’t mentioned here I recommend reading Mads Torgersens post on (from where I copied most C# 9 examples in the code in this post) https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/.

Now, stop reading and go write some code!

Introducing The WIB Limit

If you and your development team are using a Kanban board then you are familiar with the term WIP limit. WIP is short for Work In Progress and the idea is that putting a limit on the amount of ongoing work will help the team focus on the most important work and getting more work items completed. The limits will also help with identifying bottlenecks in the work flow that needs to be addressed.

I think WIP limits are great. Personally I try to work on only one thing at the time as much as possible and minimize context switching. There is however one more limit that I would like to propose, the WIB limit. WIB is short for ’Work In the Backlog’ and the goal of the limit is to avoid having the number of items in your backlog growing out of control.

The backlog problem

In my experience, backlogs with 100 or even several hundred items in them are not unusual. As time goes by more and more items are added, at a faster pace than the development team can finish the items on top. This usually goes on until the product owner goes on a cleaning frenzy and drops the majority of the items. The cycle then starts over and the backlog continues to grow.

So why is this a problem? For once, if you get a request for a feature from the organization and your response is ”Sure! I am putting it in the backlog and we’ll work on it as soon as possible”, and you have 100 other items in the backlog with higher priority, you are pretty much lying to the organization that the feature will be developed…ever. And once people starts to realize that their items aren’t being worked on they will try to find all kinds of ways around your work process.

Second, trying to keep an overview of, and prioritize between, hundreds of items is just not realistic. The work effort required to keep them up to date and in correct priority order is just too big.

Third, there will be times when you start feeling guilty for having items just lingering in the backlog for months and months, but because they have been there for so long the notes written in them will be out of date or difficult to remember what they actually meant, meaning you have to start over with any work you put in to understanding requirements and write a good user story in the first place.

The WIB limit

I suggest putting a hard limit on the number of items in the backlog. There is no exact number that I believe works for all but somewhere in the range 15 – 20 items should be the limit. It should be possible to have a pretty good overview on 20 items and keeping them prioritized.

Once the WIB limit has been reached, no new items are added to the backlog until there is free space. Any requests to add new items are rejected, justified by that there just isn’t any room for new work items at this moment.

Now, there will be times when something really urgent pops up that needs to be put high up in the backlog. When this happens, and the WIB limit has already been reached, the item with the lowest priority must be dropped and the organization has to be informed that this happened. If the item put in is really top priority, then this must be accepted.

Note that introducing a WIB limit will not in any way reduce the number of work items being completed. Instead it will help with highlighting the current work load, make it more clear what items are prioritized and why, and keep development teams from making promises they can not keep.

Learn SQL Server Administration in a Month of Lunches

I just finished a month of lunches (actually breakfasts) in the company of a book called ”Learn SQL Server Administration in a Month of Lunches” by Don Jones. As the name implies it is a book on the topic of administrating one or more database servers that runs Microsofts RDBMS software ”SQL Server”.

Book cover

This is NOT a book on database design or the programming language SQL, even though it contains a T-SQL crash course. Instead this book teaches you how to manage a SQL Server. That is, how to manage security, set up and configure auditing, monitor performance, investigate dead locks and time outs, manage back-ups, and other things that are useful for keeping a database server running smoothly.

Jones did not write this books for software developers only but for anyone who recently has become responsible for administrating a server running SQL Server and is in need of getting up to speed with the most important tasks that comes with the role. I would recommend anyone, developer or not, that are responsible for managing one or more instances of SQL Server to read this book. It is packed with tips and hands-on exercises that will quickly help you learn the most important skills needed for administrating SQL Server.

Even though the book was written when SQL Server 2012 was the most recent version out there I did not find anything that wasn’t applicable for SQL Server 2019. Even the pictures of dialogs in SQL Server Management Studio are still 100% accurate. I suppose that Microsoft does not change these if not absolutely necessary.

Now go learn some SQL Server administration!

Results in F#

I recently wrote a blog post on the Option type in F# and how to use it to represent the abscence of a value, for example when looking up a user in a database by trying to match an integer with a user id. If no user with a matching id exists, Option lets you return None. Compared to returning null, which is quite common in C#, None is a valid value and you wont risk getting a NullReferenceException when returning None.

However, Option does not let you specify any reason, like an error message, that explains what went wrong when None was returned. To remedy that, you can instead use the Result type. A Result in F# can be either Ok or Error where both can be of different types. Let’s look at the example from before, but re-written to use Result.

open System

type CustomerId = CustomerId of uint32
type Customer = { Id: CustomerId }
type Email = Email of string
type ErrorMessage = ErrorMessage of string

type StringToCustomerIdParser = string -> Result<CustomerId, ErrorMessage>
type CustomerLookup = CustomerId -> Result<Customer, ErrorMessage>
type EmailLookup = Customer -> Result<Email, ErrorMessage>
type EmailSender = Email -> unit

let toError s = ErrorMessage s |> Error
let toString (ErrorMessage msg) = msg

let userIdStringParser : StringToCustomerIdParser = fun s ->
    match UInt32.TryParse s with
    | true, num -> Ok (CustomerId num)
    | _ -> toError (sprintf "Could not parse %s to an integer" s)

let getCustomerById : CustomerLookup = fun id ->
    let getValue (CustomerId i) = i

    match id with
    | CustomerId 1u -> Ok { Id = CustomerId 1u }
    | CustomerId 2u -> Ok { Id = CustomerId 2u }
    | _ -> toError (sprintf "No customer with id %d exists" (getValue id))

let getEmailForCustomer : EmailLookup = fun customer ->
    match customer.Id with
    | CustomerId 1u -> Ok (Email "apan@bepan.se")
    | _  -> toError "Customer has no e-mail"

let sendPromotionalEmail : EmailSender = fun email ->
    ()

[<EntryPoint>]
let main argv =
    if argv.Length <> 1 then
        failwith "Usage: program <user_id>\n"

    let result = 
        userIdStringParser argv.[0]
        |> Result.bind getCustomerById 
        |> Result.bind getEmailForCustomer
        |> Result.map sendPromotionalEmail

    match result with
    | Ok _ -> printf "Email sent successfully\n"
    | Error err -> printf "%s"  (toString err)
    0 

Take a look at the code in the main function. There are several methods that return a Result and I have used Result.bind and map to create a workflow where the returnvalue from each function call is used as an input parameter to the next function, as long as the result is Ok. If any of the functions returns an Error the rest of the workflow is skipped (Result.bind will not call the next function, instead it will just return the Error from the previous function).

A constraint that is good to be aware of is that the error value type must be the same for all functions. You can see this if you look at the function type declarations that the error value type is always ErrorMessage, which is a type that just wraps a string. If different types were used it would not be possible for Result.bind and map to just return the error from the previous function, since the types would not match. There are ways around this but I won’t go into those now.

Looking at the code again. What do you think will be printed to the console if the number one is given as input, what about 2 and 3? Below is the outcome from some different runs.

$ sendEmailToCustomer 1
Email sent successfully
$ sendEmailToCustomer 2
Customer has no e-mail
$ sendEmailToCustomer 3
No customer with id 3 exists
$ sendEmailToCustomer test
Could not parse 'test' to an integer

How do you like this way of handling errors? Quite different from the usual throwing exceptions and returning null isn’t it. Personally I think that, after a bit of getting used to, this approach makes the code much easier to read and reason about. Notice that there is not a single try-catch, no null guards, and only a single if-statement in the code above.

Physical books in a connected world

Some might say that technical books, in the form that is printed on dead trees, have lost their raison d’être in the connected world we’re living in. To some extent they are right, there are many cases where it is better to look up the latest information online than to confide to a dusty old reference manual. In other cases a proper book will serve you much better than an online resource.

Some of the books in my shelf

For once, the quality level that has to be met in order to get a technical book published is just so much higher than anything posted online. If you buy a technical book you can be pretty sure that the author is an expert in his field and that and least one, in many cases several, other experts have been involved and given their input and approval.

Secondly, with a book you have all information collected in one place, usually nicely structured and with a comprehensive index at the back. I often find it just as easy to look up something in a book than it is to search for it online and in many cases the descriptions and examples in the books are much more educational which helps with the understanding on why things work as they do and not just how they work.

An argument you some times hear against buying technical books is that ”technology changes so fast that your books will be out of date before you have finished reading them”. In some cases this is true, in many cases not. The foundations on which most of the new technology is built upon have not changed in decades. Take the major programming paradigms as an example. Procedural, object oriented, and functional programming were all invented in the 50’s and 60’s and the core concepts are still the same. Hence, learning the core concepts is useful and will stay useful, regardless of the programming language you write your programs in (this is by the way something that is often overlooked when recruiting software developers where recruiters often look for experience with a particular programming language over a high level of understanding of the programming paradigm. The language used is often a minor detail, a good Java programmer will pick up C# in no time, and vice versa).
Other areas that haven’t aged much are data structures, algorithms, and relational databases. Sure, SQL server is always evolving and NOSQL databases has gained a lot of popularity recently, but the foundations laid out by Edgar F. Codd in the 1970’s are still highly relevant.

In conclusion, traditional technical books still has a place in the modern connected world. They are great for educational purposes when the goal is to learn about concepts and ideas that has proven to stay true over the years. It is also a nice feeling to grab a cup of coffee, pick up a real physical book, and flip between actual pages at a peaceful pace.

Options in F#

In the last post I compared the new Nullable reference types that were introduced in C# 8 with using Option from language-ext, which tries to mimic the functional paradigm approach to representing the abscence of a value. One of the major drawbacks of Option in C# is that there is no built in language-support, instead you have to rely on third party packages, or roll your own.

In F# however, as well as in other functional languages, Option is built in from the start and is the default way to represent a missing value. I usually don’t write code in F# but I wanted to take a look on how the scenario I used in the previous post would look like in a functional-first language so I made a test implementation in F#. Now this is just dummy code to test the scenario, in a real world application the functions would look a lot different:

open System

type UserId = UserId of uint32

type Customer =
    { Id: UserId }

type Email = Email of string

let tryParse (s: string) : UserId option =
    match UInt32.TryParse s with
    | true, num -> Some (UserId num)
    | _ -> None

let getCustomerById (id: UserId) : Customer option =
    match id with
    | UserId 1u -> Some { Id = UserId 1u }
    | UserId 2u -> Some { Id = UserId 2u }
    | _ -> None 

let getEmailForCustomer (customer: Customer) : Email option =
    match customer.Id with
    | UserId 1u -> Some (Email "apan@bepan.se")
    | _  -> None

let sendPromotionalEmail (email: Email) : unit =
    ()

[<EntryPoint>]
let main argv =
    if argv.Length <> 1 then
        failwith "Usage: program <user_id>"

    let result = 
        tryParse argv.[0]
        |> Option.bind getCustomerById 
        |> Option.bind getEmailForCustomer
        |> Option.map sendPromotionalEmail

    match result with
    | Some _ -> printfn "Email sent successfully"
    | None -> printfn "No email sent"
    0 

Note that even though F# is a statically typed language it is not required to explicitly define types for all input parameters and return values, most of the time the compiler can resolve the types so you don’t have to. In the code above I have however defined the types anyway to make it clearer how to work with Option, bind and map.

As you can see there are three functions that returns Options, tryParse that returns Option<CustomerId>, getCustomerById that returns Option<Customer>, and getEmailForCustomer that returns Option<Email>. Note that even though none of the functions takes an Option as input we are able to pipe the returned value through the functions in the main function using Option.bind and Option.map. Just like we were able to do in C# using language-ext.

Conclusion

In this simple scenario it was quite simple to port the C# implemenation to F#, so much that I would like to explore other scenarios as well and how to implement them using F#.

If using F# is an option it might be worth considering it, and get the full experience, over trying to copy the behavior by using language-ext. I will continue exploring F# and how it compares to C# in different scenarios. I believe it will be an interesting journey.

Nullable reference types compared to the Option monad

I wanted to investigate how Nullable reference types, the new big feature that was introduced in C# 8, compared to the Option type from language-ext. But let’s start with some information to set up the scene.

Nullable reference types

The way to indicate the abscence of a value in C#, as well as in many other languages, is usually to use null. For example, assume that we wish to look up a user in the database by supplying a user id. The method signature might look something like this:

public User GetUserById(int userId);

Now, this signature is a bit problematic since it does not say anything about what will happen when no user with the given userId exists. It might throw an exception, it might return a default User, or it might return null. The only way to really know is to look at the implementation. Also, if null is returned and the calling method doesn’t cover this case, we might end up with the dreaded null reference exception.

In C# 8 these problems have been addressed, by the introduction of Nullable reference types. If you turn on this feature in your project (see https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references for details) the GetUserById method can be declared like this instead:

public User? GetUserById(int userId);

Notice the questionmark after User? That indicates that this method might return null. This is a strong indication to what will happen if no user with the given user id exists. Also, the compiler will now generate warnings if you try to deference the returnvalue without first checking for null. This is nice!

The Option monad

Now, don’t be scared of the M-word. You don’t need to understand what a monad is for the following text to make sense. Later in this post I will, however, show some nice things that comes from this, but you still don’t need to understand all the underlying details (in fact, if you’re a C# developer you probably use monads all the time without even knowing it. Every type that implements IEnumerable is actually a monad).

Anyway, the idea of using an Option type comes from the functional paradigm. In F#, as an example, the option type is part of the language out of the box. In C# you can find a nice implementation of it in language-ext, which is available as a nuget package from the official nuget repository.

Using the option type the GetUserById method would get a signature like this:

public Option<User> GetUserById(int userId);

The Option type is like a container that can be either empty or contain a single value. Just like the nullable reference type, using an option is a clear indication to the caller to what to expect in the case where no user with the given user id exists.

And, just like the nullable reference type, the calling code must handle the possibility that no user is returned. Actually, using option is even more secure since there is no way to get the code to even compile without handling both possible outcomes.

Comparing the two

So, are there any benefits with using nullable reference types over the option monad, or the other way around? Well, the obvious benefit of nullable reference types is that it has built-in language support in C# starting from C# 8. No need for extra nuget packages, only a quick change in the project file and it’s enabled. It is even possible to gradually introduce it by using more fine grained control mechanisms than entire projects.

Also, nullable reference types is probably a lot easier for existing C# programmers to accept than introducing the Option type, which might look and feel a bit strange and takes a while to understand and see the benefits of. It sure feels like nullable reference types is the better option here (no pun intended).

Now, with that said, you might take the blue pill, stop reading here and remain in ignorence.
Or, you may take the red pill and I’ll show you how deep the rabbit-hole goes (did not get the reference? Shame on you! Go see The Matrix and come back here afterwards).

The problem with null is that it has no value, it’s the abscence of a value. An Option on the other hand is always a valid instance. In language-ext the Option type is implemented as a struct, meaning it can’t be null. Also, in case the Option contains a value, that value can also not be null. The implementation of Option stops any attempts to create a new Option containing a null value. This means, if you use Option you eliminate null references from your code, if you use nullable reference types they are still there.

The question that should come to mind here is, what difference does it make if I use null or not? Let me show you by an example. Assume that you have a program that takes a user id, a string to be parsed as int, as input. It looks up the user in your database then, if a user is found, it looks up the user’s e-mail address and finally, if an e-mail address for the user could be found it sends a promotional e-mail to the user. Using nullable reference types you method signatures might look like this:

public Customer? GetCustomerById(int userId);
public Email? GetEmailForCustomer(Customer customer);
public void SendPromotionalEmail(Email email);

and to cover for invalid input and possible null values, the calling code needs to look something like this:

public void SendPromoToCustomer(string id)
{
  if (int.TryParse(id, out var userId)
  {
    var customer = GetCustomerById();
    if (customer == null)
      return;
    var email = GetEmailForCustomer(customer);
    if (email == null)
      return;
    SendPromotionalEmail(email);
  }
}

Now, this is a really simple example but it clearly shows the noise that the handling of null values introduces to the code. In a large codebase, null checks like these are everywhere.

Let me show you how the code would look using Option, Bind and Do from language-ext (here comes the part where the fact that Option is a monad makes all the difference). First, let’s change the null reference type returning methods to return Option instead:

public Option<Customer> GetCustomerById(int userId);
public Option<Email> GetEmailForCustomer(Customer customer);
public void SendPromotionalEmail(Email email);

Now, the calling code can be re-written to this:

public void SendPromoToCustomer(string id)
{
  parseInt(id)
    .Bind(GetCustomerById)
    .Bind(GetEmailForCustomer)
    .Do(SendPromotionalEmail);
}

This code still handles the possibility that the id string might not be possible to parse to an int, that GetCustomerById might not return a user, and that an e-mail address might be missing, but since we always have a valid instance to work with, an Option, we can just push it through the workflow and let the framework (language-ext) handle the error cases.

Bind and Do are extensions methods on Option. They inspect the content of the Option and if it contains a value the function given as parameter will be called with the value of the Option as a parameter. The return value of the function will then be used in the next call to Bind or Do. However, if the Option does not contain any value, the function will not be called. Instead, a new empty Option will be returned directly by Bind or Do.

Conclusion

I truly believe that Option is a better alternative to null for representing the abscence of a value. However, I also understand that using Option and language-ext is a big change which requires many developers to re-think and change the way they think and reason about handling these cases. Hence, I would not introduce this into a large existing codebase where developers are used to handling null. In that case I would recommend introducing nullable reference types, if possible (C# 8 is not supported on older frameworks).

But, starting a new, smaller, project I would opt for using language-ext and trying to get away from null as much as possible.

If you are interested in learning more, I recommend that you take a look at the book review that I wrote on the book ”Functional programming in C#”, https://ericbackhage.net/c/book-review-functional-programming-in-c/

Book review: Functional programming in C#

I have been interested in functional programming for quite some time, experimenting with both F# and Clojure as well as trying out some Scala. But I must admit that I have never really put full focus on it for any longer period, not until I found this book:

Book cover

Functional programming in C# – How to write better C# code is a book by Enrico Buonanno, a CS graduate from Columbia University with over 15 years of experience as a developer, architect, and trainer. It is published by Manning and you can find it at https://www.manning.com/books/functional-programming-in-c-sharp.

What made this book appealing was that it is written for developers who are fluent in C#, a language that I know quite well, meaning I did not have to struggle with both a new language and all the new concepts and ways to think that comes with functional programming. In retrospect this was a really nice way to learn what functional programming is all about.

This book is not for the beginner programmer. It goes into several advanced topics in depth and I would only recommend it to an experienced C# developer who is willing to spend a lot of time and energy on learning about functional concepts such as immutability, functors, monads, partial applicaction, currying and the likes.

With that said, if the above description fits you, I can really recommend that you give this book a try. It describes a lot of concepts and has a lot of sample code and coding excercises. The first eight chapters all ends with a bunch of challenging excercises for the reader and there is also a github repository available that includes the authors own functional library and excercises and solutions from the book. You can find the repository at https://github.com/la-yumba/functional-csharp-code.

The only critique I can give is that I think that it would have been better if the author used the well established language-ext library instead of developing his own. When comparing the two I get impression that the authors library is pretty much a subset of language-ext and does not add anything I don’t get from language-ext.

I feels nice to finally understand what a monad is. My next step on this journey will probably be to take a deep dive in a pure functional language (like Haskell).

.NET under the hood – The ’null’ keyword

I assume that you are familiar with the null keyword in C#. It represents a null reference, one that does not reference any object, and even though it has no type it can be assigned to any reference of any type.

Null as a concept is quite abstract. It is often used to represent the abscence of a value, so in itself it has no concrete representation. Well, this may work in theory, but once you boil it down to machine code you have to represent null somehow. In this post I will discuss some Common Intermediate Language (CIL) code related to null and also look at some implementation details of the dotnet runtime. But let’s start with some C# code:

string s = "A string";
if (s == null)
    Console.WriteLine("s is null");

In the code above we have an object, s, of type string which we compare to see if it is equal to null. Let’s compile this and see what the compiler does with this code. Don’t worry if you’re not used to reading CIL, I will explain what the opcodes does. Using the tool ildasm you can inspect the CIL-code generated by the compiler. For a main method containing the above code the compiler will generate the following CIL-code:

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init (string V_0,
           bool V_1)
  IL_0000:  nop
  IL_0001:  ldstr      "A string"
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldnull
  IL_0009:  ceq
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  brfalse.s  IL_001a
  IL_000f:  ldstr      "s is null"
  IL_0014:  call       void [System.Console]System.Console::WriteLine(string)
  IL_0019:  nop
  IL_001a:  ret
} // end of method Program::Main

Instructions on line IL_0001 to IL_0007 will push the string ”A string” onto the stack. Then on line IL_0008 comes an interesting op-code, ldnull. This op-code means ”push null onto the stack”. The next op code, ceq, means ”check if [the two items on top of the stack are] equal”. But wait a minute…if null doesn’t have a value, how can it be put onto the stack? And how can you compare it with another value? Something fishy is going on here.

To understand what happens when ldnull is executed we need to take a look at the implementation of the runtime engine. Fortunately the source code of the dotnet runtime is available on GitHub, https://github.com/dotnet/runtime/ for anyone to dive into.

After browsing the code for a while I found an interesting piece of code in a file called interpreter.cpp, a function with the signature void Interpreter::LdNull() which seems to be executed when CEE_LDNULL is encountered. Looking in the file opcode.def it becomes obvious that CEE_LDNULL means opcode ldnull. The interesting part of the LdNull functions are the following two lines of C++ code:

OpStackTypeSet(m_curStackHt, InterpreterType(CORINFO_TYPE_CLASS));
OpStackSet<void*>(m_curStackHt, NULL);

This code sets the type of the stack variable to class and pushes a void pointer with value NULL, which is defined as 0 (zero), onto the operand stack.

If you are familiar with C and C++ you will recognize this. It is a regular null pointer (https://www.learncpp.com/cpp-tutorial/6-7a-null-pointers/). And for those of you who aren’t familiar with null pointers, a pointer holds an address to a place in your computer’s memory where a value (or several values) are stored and a null pointer is a pointer that has the value 0, which is not a valid memory address for your program to store any data.

So, in summary, null in .NET is, in practice, a pointer to memory address 0 (zero).

A functional approach to error handling in C#

Imagine that you want to write a simple console application that queries the user for two integers, divides the first integer with the second, and writes the result to the console window. What can go wrong in a simple program like this? The first thing that comes to mind is probably that the user might enter something other than integers, like ”rainbow unicorns” or ”l33t h4x0r”. Secondly, he might enter a zero as the second integer, trying to crash the program by having it perform a division by zero (throws a DivideByZeroException).

In order to handle these cases you can use the Int32.TryParse method for parsing the input and a try-catch statement to cover a possible division by zero. Your code might look something like the following:

static void Main()
{
    var numerator = QueryUser("Numerator: ");
    var denominator = QueryUser("Denominator: ");

    if (int.TryParse(numerator, out var n) &amp;&amp;
        int.TryParse(denominator, out var d))
    {
        try
        {
            WriteLine($"{numerator} / {denominator} = {n / d}");
        }
        catch (Exception e)
        {
            WriteLine($"An error occurred: {e.Message}");
        }
    }
    else
    {
        WriteLine("Only integers are allowed as input.");
    }
}

In the code above the QueryUser method is a simple helper method that writes a message to the console and reads the user’s response. The implementation follows the standard imperative pattern using if-statements for controlling the program flow and the standard OOP error handling using try-catch statements.

Now, let me present to you a different approach for handling lack of values and possible errors. It involves using the C# Functional Programming Language Extensions, language-ext, by Paul Louth.

static void Main()
{
    var numerator = QueryUser("Numerator: ");
    var denominator = QueryUser("Denominator: ");

    var result =
        from n in Some(numerator).Bind(parseInt)
        from d in Some(denominator).Bind(parseInt)
        select Divide(n, d);

    result.Match(
        Some: s => s.Match(
            Succ: res => WriteLine($"{numerator} / {denominator} = {res}"),
            Fail: err => WriteLine($"An error occurred: {err.Message}")),
        None: () => WriteLine("Only integers are allowed as input."));
}

If you haven’t seen this approach to error handling before it might be difficult to understand what’s going on here. Where is the if-statement and the try-catch block? And what is Some, Bind, and Match?

Explaining everything in detail would require more than what is possible in a single blog post, and if you are interested in the details I recommend reading Paul Louths presentation of language-ext and also the great book Functional Programming in C# which explains all the details of the Option- and Either monads and how Monadic Bind is used to chain monadic returning functions together.

However, to understand the code above you need to know that QueryUser has not been changed, it will still return whatever the user enters, which might not be possible to parse as an integer. Some is a function that is defined in language-ext. It takes a value, in this case of type string, and lifts it into an Option-type. An Option is a container that can either contain a value, Some, or be empty, None. In this case the Option-container will have a value, the string that the user entered.

Next comes Bind. What Bind does is to take the Option and apply it’s value to the function that is given as argument to Bind. In this case Bind takes the string that the user entered and calls the parseInt function with the string as parameter. Now if the user have supplied a value that can be parsed as an int then Bind will return an Option containing the resulting value. However, if the value could not be parsed then Bind will return an Option containing None. This replaces the TryParse calls in the imperative code.

Now that we have two Option variables, n and d, we use select with the Divide function to calculate the result. It is not visible in the above code but this use of select depends on a special implementation of Select and SelectMany that accepts Option-types as input parameters (you might be familiar with the Select and SelectMany implementations for IEnumerable that is part of LINQ, these are similar but for Option).

The Divide function is an implementation of the Try delegate of language-ext which handles any possible exceptions that might occur and wraps them in a Result type. This might be a lot to wrap your head around, but if you’ve gotten this far you might be wondering about the Match functions at the end.

So, the type of the result variable is Option<Result<int>> where the outer type, Option is Some iff both the input strings were successfully parsed as int values (otherwise None), and the Result is Succ (success) iff no exception were thrown when performing the division (otherwise Fail). Match is used to check which of these four possible cases the result ended up as and outputs different texts depending on the outcome.

There are quite a lot of new concepts to understand and a very different way of thinking about errors if you want to use this approach to error handling. The small toy examples that you have to use in blog posts like this does not show any real benefits either so you might be very sceptic to all this right now. The value of the functional approach is that, once you understand the concepts, it makes your code much easier to understand and reason about. Traditional OOP and imperative code sprinkled with if-statements and exceptions being thrown and caught at different levels of the code quickly makes it extremely hard to follow. The functional approach pushes the error handling code to the end (the Match in the code above).

Finally I would like to recommend Scott Wlaschin’s introduction to Railway Oriented Programming which also includes a link to his presentation at NDC on the topic.