This entry is part 1 of 1 in the series Functional Programming
  • What the Hell is Functional Programming in C#?

Why Functional Programming

I’m starting a series of posts on functional programming in C#. The series is kind of a preview of a video course I’m working on right now which will be released somewhere at the end of February.

So, you may ask yourself again “why would I need to learn functional programming”? You may also think that you’ll never use a truly functional programming language. However, you don’t need to learn a truly FP language to harness the power of FP ideas. Apart from that, you’ll get a better developer learning new programming concepts and looking at the same code base from other perspectives, considering different concepts. Believe me, after learning new fundamental programming concepts, you’ll get a fresh look at what you did before.

If I’d need to mark out the benefits of a functional programming style, I would list the following:

  • Minimizing the code base, functional style, in the end, leads to the more understandable and shorter code
  • FP leads to constructing more composable components which have very high reusability

These benefits are very important especially in enterprise development field since domains become more difficult to understand on every year basis.

There is another benefit we haven’t marked out yet. Concurrency. Didn’t expect? Yes, indeed, a truly functional program is safe for concurrent access by default. The main problem of concurrent access is the possibility of damaging the shared state. In a functional programming, there is nothing to damage since there is no shared state. This is also one of the reasons which explain why functional programs are safer. They are more predictable.

Core Concepts

The core concepts of the functional programming are:

  • Immutability
  • Purity (absence of side effects)

These are more notions in the functional programming, however, this article is suited for beginners and I want to uncover the basics.

Immutability

Immutability is one of the core concepts in functional programming. When we’re talking about mutability, we imply mutable or immutable objects. So, what does it mean for an object to be immutable? It means that such an object doesn’t mutate or change in other words its internal state. Juniors often get confused hearing about immutability for the first time. Indeed, how is that possible to implement an immutable type? However, any C# developer can recall that the string type is immutable. When you change a string instance, you get a new modified string instance as a result. The initial instance stays unchanged. This is immutability in essence.

Ok then, let’s look at a very simple code snippet. Here is the Character class.

[code lang=”csharp”] public class Character {
public int Health { get; private set; } = 100;

public void Hit(int damage) {
Health -= damage;
}
}[/code]

Is this class immutable? No, this class is mutable. The Hit method mutates the internal state, it changes the value of the Health property. We can’t say that this is a very bad piece of code, however, we can make it better. We can make it immutable automatically making it safe for concurrent access at least. Actually, the benefits are more profound, and you’ll see that later. So, how to make this type immutable? Easily. Here is the refactored version:

[code lang=”csharp”] public class Character {
public int Health { get; } = 100;

public Character Hit(int damage) {
return new Character(Health – damage);
}
}[/code]

Look at this. The Hit method now returns a new instance on each call. It doesn’t mutate the internal state anymore. This is exactly how the string type is implemented (well, not quite but the idea is similar).

Let’s look at another example which demonstrates how mutability reduces readability. Look at the Rectangle class:

[code lang=”csharp”] public class Rectangle {
public int Width { get; private set; }
public int Height { get; private set; }

public Rectangle(int width, int height) {
Width = width;
Height = height;
}

public void Scale(int factor) {
Width *= factor;
Height *= factor;
}
}[/code]

This type is mutable since the Scale method mutates the internal state, the width and height properties. The next type we have here is called Ellipse.

[code lang=”csharp”] public class Ellipse {
public double Radius { get; private set; }

public Ellipse(Rectangle rect) {
Radius = Math.Sqrt(rect.Width * rect.Width +
rect.Height * rect.Height) / 2;
}
}[/code]

it takes a Rectangle instance in its constructor. It takes the rectangle to draw itself around that rectangle.
We don’t have a full-blown implementation since it doesn’t matter from the learning perspectives. Now is the most interesting thing. Let’s look at the client’s code.

[code lang=”csharp”] public class ClientCode {
public void Caller() {
var rect = new Rectangle(10, 20);
Ellipse el = new Ellipse(rect);
rect.Scale(2);
}
}[/code]

the caller creates an instance of the Ellipse type passing the previously created Rectangle instance. Finally, it scales up the rectangle.

Aha… interesting, nice. Looking only at this piece of client’s code can you understand what will happen to the ellipse after resizing the rectangle? Seems like we mutate the internal state of the Rectangle instance, but will the size of the ellipse change correspondingly? This example demonstrates how mutability reduces the readability.

Let’s look at how we can improve the design of this toy example. To make the Rectangle immutable we can do the same trick we’ve done to the Character type.

[code lang=”csharp”] public class Rectangle {
public int Width { get; private set; }
public int Height { get; private set; }

public Rectangle(int width, int height) {
Width = width;
Height = height;
}

public Rectangle Scale(int factor) {
return new Rectangle(Width * factor, Height * factor);
}
}[/code]

Let’s look at how will the client’s code change.

[code lang=”csharp”] public class ClientCode {
public void Caller() {
var rect = new Rectangle(10, 20);
Ellipse el = new Ellipse(rect);

Rectangle rectangle = rect.Scale(2);
}
}[/code]

Now we see that the Scale method returns a new instance of the Rectangle type. That, of course, means that the Ellipse stays unchanged since the internal state of the Rectangle type obviously stays unchanged in the first place.

Purity and Side Effects

So, what is a side effect? Actually, you had to hear of side effects since every one of us ever took a medication. So, I’m sure you know what is a side effect of a medication. Simply put, when we take a medication we have an expectation regarding a direct result – curing the disease, however, sometimes we observe something unexpected – a rash on the skin. That is a side effect. Usually, we tend to think of side effects as something bad. Side effects in programming are similar but they are not always bad.

In terms of programming, a side effect is an observable change made to the state of the system. Actually, many C# developers, especially juniors, immediately become puzzles since they can’t imagine a program which doesn’t mutate any state. Ok, let’s talk about it in more details.

The definition we gave for a side effect is a little bit blurred. Let’s have a look at some examples. We don’t need to run Visual Studio for that, I’ll just show you the code snippets right on the slides.

So, here is the first example.

[code lang=”csharp”] public double Add(double a, double b) {
return a + b;
}[/code]

Does this function have a side effect? Well, probably not, because it doesn’t hide anything, it takes two arguments and honestly returns the expected result. Ok, let’s go to the next one.

[code lang=”csharp”] public int Divide(int a, int b) {
return a / b;
}[/code]

Does this function have a side effect? Look more carefully. Can it produce some kind of side effect which is observable from the system’s point of view? Indeed, this function has side effects. What will happen if the second argument’s values would be equal to zero? An exception will be thrown in such a case. And an exception is always can be considered a side effect. Division guarantees by its signature that the result of an integer type will be returned, however, it is a lie since there is a case which violates the declared signature.

We refer to truly mathematical functions as to pure functions. However, you should understand that we treat functions as pure only to some extent. Don’t get this concept literally. For example, in general, we can treat the previous function which adds two values as pure but is that true that it can’t fail ever? Of course not. An exception can be thrown at the runtime at any time in a managed environment. This is the sad truth, however, any program depends on such factors as the global state of RAM managed by the Operating System.

So, again, don’t get the concept of side effects literally. We make assumptions to some extent. We can’t avoid such assumptions, otherwise, we can’t treat any function in the world as truly pure.

So, when we talk about side effects and purity we abstract away all the factors which are outside of our control. But again, the function which allows division by zero and which at the same time doesn’t reflect it in its signature is indeed not pure.

How can we make that function to be more honest? For example, we can declare it as a function which returns a nullable int and returns null in case of division by zero.

[code lang=”csharp”] public int? Divide(int a, int b) {
if(b==0) return null;
return a / b;
}[/code]

After that we need to reflect that null-value is a special case in the XML-comments or in the documentation. You could argue that instead, we could just reflect in comments that in case of division by zero an exception is going to be thrown. However, returning nullable int is a more robust option from the statically typed language point of view. Though, not an ideal one.

We could change the signature by accepting some kind of new type which defines the allowed range more precisely, excluding zeroes from the range. Here is an example.

[code lang=”csharp”] public class NonZeroInteger
{
public int Number { get; }

public NonZeroInteger(int number) {
Number = number;
if (number == 0)
throw new ArgumentException();
}
}
public int Divide(int a, NonZeroInteger b) {
return a / b.Number;
}[/code]

We rolled out a new type called NonZeroInteger which encapsulates a number. It throws an exception in case of an invalid argument passed into its constructor. Now, everything is clear statically. That’s a great benefit, however, the question is “is it worth to roll out the whole new class”? Well, the answer depends on the concrete case. It depends on the value brought to the system by introducing a new type. If that value overweights the increased complexity, then everything is fine.

I started this rant to show what are side effects, what can be possibly done to remove them and that sometimes we may want to stay with side effects. I will say a couple of words about when side effects are fine in a minute. Let’s look at the next example.

[code lang=”csharp”] public double Add(double a, double b) {
try {
Console.WriteLine($"a={a}, b={b}");
} catch(Exception ex) { }
return a + b;
}[/code]

This function returns a sum of two doubles. However, it logs the information down to the console or it may have been writing it to a file, for example. How do you think, is this function pure?

Well, most likely, this function is pure indeed. In 99% of cases, logs are not observable from the system’s point of view. If logging has some influence on the system’s behavior, then such a function can be treated as impure.

Let’s look at the next example.

[code lang=”csharp”] public class SideEffect {
private int state = 0;
public int Calc(int input) {
state = input;
return input–;
}
}[/code]

Calc mutates the internal state of the object. It assigns a new value to the local field. This function is impure since such a mutation is an obvious side-effect. The next example if a classic example of a side effect. The first sign that the function has some kind of side-effect is that it returns void. It means that the function does something and it doesn’t return anything as a response. Let’s get to the next example.

[code lang=”csharp”] public int GetTheAnswer()
{
return 42;
}[/code]

This function is the definition of purity. It always returns the same value, it doesn’t mutate anything and it has no side effects. Ok, that was a simple function, let’s get to the next one. The next example is an interesting one.

[code lang=”csharp”] public int GetSecond()
{
return DateTime.Now.Second;
}[/code]

You see the function which returns current second. Is this function pure or not? This function is not pure since it returns different values each time being called. It doesn’t mean this function is bad. Right now, we’re only trying to understand what purity means in regard to the formal definition.

Ok, you’ve seen which functions can be treated as pure and which can’t. As I’ve said already, the impurity doesn’t mean something bad. In this article, you learned what side effects are in essence. The next post will uncover the benefits of expressions over statement and which constructs do we have in C# at our disposal to make code more exressive. Stay tuned.