1 / 83100%
WHAT IS FUNCTIONAL PROGRAMMING?
There are a few basic concepts in Functional Programming, many of which
have fairly obscure names for what are otherwise not terribly difficult
concepts to understand. I’ll try and lay them out here as simply as I can.
Is it a Language, an API, or what?
No, Functional Programming isn’t a language or a 3rd party plug-in library in
Nuget, it’s a paradigm. What do I mean by that? There are more formal
definitions of paradigms, but I think of it as being a style of programming.
Like a guitar might be used as the exact same instrument, but to play many,
often wildly different, styles of music, so also some programming languages
offer support for different styles of working.
Using Functional Programming techniques, Delegate types can be composed
together to create larger, more complex functions from smaller, functional
building blocks. Like lego bricks being placed together to make a model
Millennium Falcon, or whatever you prefer. This is the real reason this
paradigm is called Functional Programming. It’s not, as the name suggests,
that the code written in other paradigms don’t function at all. Why would
anyone ever use them if they didn’t?
In fact - a rule of thumb for you. If there’s a question, Functional
Programming’s answer will amost certainly be “Functions, Functions and
more Functions”.
Expressions Rather than Statements
A couple of definitions are required here.
Expressions are discrete units of code that evaluate to a value. What do I
mean by that?
In its simplest form, these are expressions:
const exp1 = 6;
const exp2 = 6 * 10;
We can feed values in too, to form our expressions, so this is one as well:
function int AddTen(int x) => x + 10;
This too. It does carry out an operation - i.e. evaluate a boolean, but it’s used
ultimately to return a bool, so it’s an expression:
function bool IsTen(int x) => x == 10;
you can also consider ternary if statements to be expressions, if they’re
used purely for determinging a value to return:
var randomNumber = this._rnd.Generate();
var message = randomNumber == 10
? "It was ten"
: "it wasn't ten";
A quick rule of thumb - if there’s a single equals sign in the code, it’s likely
to be an expression. There’s some gray area in that rule. Calls to other
functions could have all sorts of unforseen consequences. It’s not a bad rule
to keep in mind, though.
Statements on the other hand are pieces of code that don’t evaluate to a
value. These take the form more of instructions. Either an instruction to the
executing environment to change the order of execution via keywords like
if, where, for, foreach, etc. or calls to functions that don’t return
anything - and by implication instead carry out some sort of operation.
Something like this:
this._thingDoer.GoDoSomething();
Another rule of thumb3 if there is no equals sign, it is definitely a statement.
Expression-based Programming
If it helps, think back to mathematics lessons from your school days.
Remember those lines of working you used to have to produce when you
were producing your final answer? Expression-based programming is like
that. On your pages of working, you couldn’t go back and retrospectively
change what you’d already written -once you’d put it on the paper, it was
there forever.
Think of programming with expressions in the same way. Each line is either
a final calculation to be returned, or a step in the process, which can only be
a constant value, based perhaps on previous steps. But the point is that you
can’t go back and change what you’ve already done.
This might seem like an impossibility, almost like being asked to program
with your arms tied behind your back. It’s entirely possible though, and not
even necessarily difficult. The tools have mostly been there for about a
decade in C#, and there are plenty of more effective structures.
After a little experience working in this manner, it will actually seem odd and
even a little awkward and clunky to go back to the old way.
Functional programming is also as old as Object-Orientated coding - if not
older. I’ll talk more about its origins later, but for now just be aware that it is
nothing new, and the theory behind it not only predates OO, but largely also
the computing industry itself.
It’s also worth noting that you can combine paradigms, like mixing rock and
jazz. Not only can they combine, but there are times when you can use the
best features of each to produce a better end result.
Using Functional Programming techniques, Delegate types can be composed
together to create larger, more complex functions from smaller, functional
building blocks. Like lego bricks being placed together to make a model
Millennium Falcon, or whatever you prefer. This is the real reason this
paradigm is called Functional Programming. It’s not, as the name suggests,
that the code written in other paradigms don’t function at all. Why would
anyone ever use them if they didn’t?
In fact - a rule of thumb for you. If there’s a question, Functional
Programming’s answer will amost certainly be “Functions, Functions and
more Functions”.
Expressions Rather than Statements
A couple of definitions are required here.
Expressions are discrete units of code that evaluate to a value. What do I
mean by that?
In its simplest form, these are expressions:
const exp1 = 6;
const exp2 = 6 * 10;
We can feed values in too, to form our expressions, so this is one as well:
function int AddTen(int x) => x + 10;
This too. It does carry out an operation - i.e. evaluate a boolean, but it’s used
ultimately to return a bool, so it’s an expression:
function bool IsTen(int x) => x == 10;
you can also consider ternary if statements to be expressions, if they’re
used purely for determinging a value to return:
var randomNumber = this._rnd.Generate();
var message = randomNumber == 10
? "It was ten"
: "it wasn't ten";
A quick rule of thumb - if there’s a single equals sign in the code, it’s likely
to be an expression. There’s some gray area in that rule. Calls to other
functions could have all sorts of unforseen consequences. It’s not a bad rule
to keep in mind, though.
Statements on the other hand are pieces of code that don’t evaluate to a
value. These take the form more of instructions. Either an instruction to the
executing environment to change the order of execution via keywords like
if, where, for, foreach, etc. or calls to functions that don’t return
anything - and by implication instead carry out some sort of operation.
Something like this:
this._thingDoer.GoDoSomething();
Another rule of thumb3 if there is no equals sign, it is definitely a statement.
Expression-based Programming
If it helps, think back to mathematics lessons from your school days.
Remember those lines of working you used to have to produce when you
were producing your final answer? Expression-based programming is like
that. On your pages of working, you couldn’t go back and retrospectively
change what you’d already written -once you’d put it on the paper, it was
there forever.
Think of programming with expressions in the same way. Each line is either
a final calculation to be returned, or a step in the process, which can only be
a constant value, based perhaps on previous steps. But the point is that you
can’t go back and change what you’ve already done.
This might seem like an impossibility, almost like being asked to program
with your arms tied behind your back. It’s entirely possible though, and not
even necessarily difficult. The tools have mostly been there for about a
decade in C#, and there are plenty of more effective structures.
After a little experience working in this manner, it will actually seem odd and
even a little awkward and clunky to go back to the old way.
Programming paradigms come in many, many flavors1 but for the sake of
simplicity I’m only going to talk about the two most common in modern
programming:
Imperative
This was the only type of programming paradigm for quite a long time.
Procedural and Object Orientated (OO) belong to this category. These
styles of programming involve more directly instructing the executing
environment with the steps that need to be executed in detail, i.e. Which
variable contains which intermediate steps and how the process is carried
out step-by-step in minute detail. This is programming as it usually gets
taught in school/college/university/at work [delete where appropriate].
Declarative
In this programming paradigm we’re less concerned with the precise
details of how we accomplish our goal, the code more closely resembles
a description of what is desired at the end of the process, and the details
(including things such as order of execution of the steps) are left more in
the hands of the execution environment. This is the category Functional
Programming belongs to. SQL also belongs here, so in some ways
Functional Programming more closely resembles SQL than OO. When
writing SQL statements you aren’t concerned with what the order of
operations are (it’s not really SELECT then WHEN then ORDER BY),
you aren’t concerned with how exactly the data transformations are
carried out in detail, you just write a script that effectively describes the
desired output. These are some of the goals of Functional C# as well, so
those of you with a background working with SQL Server or other
relational databases might find some of the ideas coming up easier to
grasp than those that haven’t.
There are many, many more paradigms besides these, but they’re well
beyond the scope of this book.
The Properties of Functional Programming
For the next few sections, I’m going to talk about each of the properties of
Functional Programming, and what they really mean to a developer.
Immutability
If something can change then it can also said that it can mutate, like a
Teenage Mutant Ninja2 Turtle. The other way of saying something can
mutate is that it is mutable. If, on the other hand, something cannot change at
all, then it is immutable.
In programming, this referrs to Variables that have their value set upon being
defined, and after that point they may never be changed again. If a new value
is required, then a new variable should be created, based on the old one. This
is how all variables are treated in Functional code.
It’s a slightly different way of working compared to Imperative code, but it
ends up producing programs that more closely resemble mathematical
working, and encourages good structure, and more predictable - and hence
robust - code. Using Functional Programming techniques, Delegate types
can be composed together to create larger, more complex functions from
smaller, functional building blocks. Like lego bricks being placed together to
make a model Millennium Falcon, or whatever you prefer. This is the real
reason this paradigm is called Functional Programming. It’s not, as the
name suggests, that the code written in other paradigms don’t function at all.
Why would anyone ever use them if they didn’t?
In fact - a rule of thumb for you. If there’s a question, Functional
Programming’s answer will amost certainly be “Functions, Functions and
more Functions”.
Expressions Rather than Statements
A couple of definitions are required here.
Expressions are discrete units of code that evaluate to a value. What do I
mean by that?
In its simplest form, these are expressions:
const exp1 = 6;
const exp2 = 6 * 10;
We can feed values in too, to form our expressions, so this is one as well:
function int AddTen(int x) => x + 10;
This too. It does carry out an operation - i.e. evaluate a boolean, but it’s used
ultimately to return a bool, so it’s an expression:
function bool IsTen(int x) => x == 10;
you can also consider ternary if statements to be expressions, if they’re
used purely for determinging a value to return:
var randomNumber = this._rnd.Generate();
var message = randomNumber == 10
? "It was ten"
: "it wasn't ten";
A quick rule of thumb - if there’s a single equals sign in the code, it’s likely
to be an expression. There’s some gray area in that rule. Calls to other
functions could have all sorts of unforseen consequences. It’s not a bad rule
to keep in mind, though.
Statements on the other hand are pieces of code that don’t evaluate to a
value. These take the form more of instructions. Either an instruction to the
executing environment to change the order of execution via keywords like
if, where, for, foreach, etc. or calls to functions that don’t return
anything - and by implication instead carry out some sort of operation.
Something like this:
this._thingDoer.GoDoSomething();
Another rule of thumb3 if there is no equals sign, it is definitely a statement.
Expression-based Programming
If it helps, think back to mathematics lessons from your school days.
Remember those lines of working you used to have to produce when you
were producing your final answer? Expression-based programming is like
that. On your pages of working, you couldn’t go back and retrospectively
change what you’d already written -once you’d put it on the paper, it was
there forever.
Think of programming with expressions in the same way. Each line is either
a final calculation to be returned, or a step in the process, which can only be
a constant value, based perhaps on previous steps. But the point is that you
can’t go back and change what you’ve already done.
This might seem like an impossibility, almost like being asked to program
with your arms tied behind your back. It’s entirely possible though, and not
even necessarily difficult. The tools have mostly been there for about a
decade in C#, and there are plenty of more effective structures.
After a little experience working in this manner, it will actually seem odd and
even a little awkward and clunky to go back to the old way.
DateTime and String are both immutable data structures in .NET. You
may think you’ve altered them, but behind the scenes every alteration creates
a new item on the stack. This is why most new developers get the talk about
concatenating strings in For loops.
Higher-order Functions
These are functions that are passed around as variables. This may be either as
local variables, parameters to a function or return values from a function.
The Func<T,TResult> or Action<T> delegate types are perfect
examples of this:
Func<int, int, string> Add = (x, y) => $"{x} + {y} =
{x+y}";
Action<string> LogMessage = x =>
this.Logger.LogInfo($"message received: {x}");
Both of these types are references to functions stored in variables, and which
can be called as functions. The only difference between a Func and Action is
that the Action has no return value - i.e. It’s a void return type. The code
above was entirely equivalent to this:
function string Add(int x, int y)
{
return $"{x} + {y} = {x + y}";
}
function void LogMessage(string x)
{
this.Logger.LogInfo($"message received: {x}");
}
The big advantage of using these Delegates types is they’re stored in
variables that can be passed around the codebase. They can be included as
parameters to other functions, or as return types. Used properly, they’re
among the most powerful features of C#.
Using Functional Programming techniques, Delegate types can be composed
together to create larger, more complex functions from smaller, functional
building blocks. Like lego bricks being placed together to make a model
Millennium Falcon, or whatever you prefer. This is the real reason this
paradigm is called Functional Programming. It’s not, as the name suggests,
that the code written in other paradigms don’t function at all. Why would
anyone ever use them if they didn’t?
In fact - a rule of thumb for you. If there’s a question, Functional
Programming’s answer will amost certainly be “Functions, Functions and
more Functions”.
Expressions Rather than Statements
A couple of definitions are required here.
Expressions are discrete units of code that evaluate to a value. What do I
mean by that?
In its simplest form, these are expressions:
const exp1 = 6;
const exp2 = 6 * 10;
We can feed values in too, to form our expressions, so this is one as well:
function int AddTen(int x) => x + 10;
This too. It does carry out an operation - i.e. evaluate a boolean, but it’s used
ultimately to return a bool, so it’s an expression:
function bool IsTen(int x) => x == 10;
you can also consider ternary if statements to be expressions, if they’re
used purely for determinging a value to return:
var randomNumber = this._rnd.Generate();
var message = randomNumber == 10
? "It was ten"
: "it wasn't ten";
A quick rule of thumb - if there’s a single equals sign in the code, it’s likely
to be an expression. There’s some gray area in that rule. Calls to other
functions could have all sorts of unforseen consequences. It’s not a bad rule
to keep in mind, though.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
Statements on the other hand are pieces of code that don’t evaluate to a
value. These take the form more of instructions. Either an instruction to the
executing environment to change the order of execution via keywords like
if, where, for, foreach, etc. or calls to functions that don’t return
anything - and by implication instead carry out some sort of operation.
Something like this:
this._thingDoer.GoDoSomething();
Another rule of thumb3 if there is no equals sign, it is definitely a statement.
Expression-based Programming
If it helps, think back to mathematics lessons from your school days.
Remember those lines of working you used to have to produce when you
were producing your final answer? Expression-based programming is like
that. On your pages of working, you couldn’t go back and retrospectively
change what you’d already written -once you’d put it on the paper, it was
there forever.
Think of programming with expressions in the same way. Each line is either
a final calculation to be returned, or a step in the process, which can only be
a constant value, based perhaps on previous steps. But the point is that you
can’t go back and change what you’ve already done.
This might seem like an impossibility, almost like being asked to program
with your arms tied behind your back. It’s entirely possible though, and not
even necessarily difficult. The tools have mostly been there for about a
decade in C#, and there are plenty of more effective structures.
After a little experience working in this manner, it will actually seem odd and
even a little awkward and clunky to go back to the old way.
Referential Transparency
This is a scary-sounding word for a simple concept. There is a concept in
functional programming of “pure functions”. These are functions with the
following properties:
They make no changes to anything outside of the function. No state can
be updated, no files stored, etc.
Given the same set of parameter values, they will always return the
exact same result. No. Matter. What. No matter what state the system is
in.
They don’t have any unexpected side effects. Exceptions being thrown
is included in that.
The terms comes from the idea that given the same input, the same output
always results, so in a calculation you can essentially swap the function call
with the final value, given those inputs. In this example:
var addTen = x => x + 10;
var twenty = addTen(10);
The call to addTen with a parameter of 10 will always evaluate to 20, with no
exceptions. There are no possible side effects in a function this simple, either.
Consequently, the reference to addTen(10) could in principle be exchanged
for a constant value of 20 with no side effects. This is referential integrity.
Here are some pure functions:
public int Add(int a, int b) => a + b;
public string SayHello(string name) => "Hello " +
(string.IsNullOrWhitespace(name)
? "Unknown Person"
: name);
Note no side effect can occur (I made sure a null check was included with the
string) and nothing outside the function is altered, only a new value
generated and returned.
Here are impure versions of those same functions:
public void Add(int a) => this.total += a;
public string SayHello() => "Hello " + this.Name;
In both of these cases there are reference to properties of the current class that
are beyond the scope of the function itself. The Add function even modifies
that state property. No null check on the SayHello function either. None of
this allows these to be considered “pure” functions.
How about these?
public string SayHello() => "Hello " + this.GetName();
public string SayHello2(Customer c)
{
c.SaidHelloTo = true;
return "Hello " + (c?.Name ?? "Unknown Person);
}
public string SayHello3(string name) =>
DateTime.Now().ToString() + " - Hello " + (name ??
"Unknown Person);
None of these are pure.
SayHello relies on a function outside itself. If a function had to be used for
retrieving the name, I’d re-write this with a Func<T,TResult> delegate
to inject the functionality safely into our SayHello function.
SayHello2 modifies the object being passed in - a clear side effect from use
of this function. Passing objects by reference and modifying them like this
isn’t all that unusual a practice in object-orientated code, but it’s absolutely
not a thing done in functional programming. I’d proabably make this pure by
separating out the update to the object properties and the processing of
saying hello into separate funtions.
SayHello3 uses DateTime.Now(), which returns a different value each
and every time it’s ever used. The absolute oposite of a pure function. I’d
fix this by adding a DateTime parameter to the function and passing the
value in.
referential transparency is one of the features that massively increases the
testability of functional code. It does mean that other techniques have to be
used to track state, I’ll get into that later.
There is also a limit to how much “purity” we can have in our application,
especially once we have to interact with the outside world, the user, or some
3rd party libraries that don’t follow the functional paradigm. In C#, we’re
always going to have to make compromises here or there.
There’s a metaphor I usually like to wheel out at this point. A Shadow has
two parts: the Umbra and Penumbra4. The Umbra is the solid dark part of a
shadow, most of the shadow in fact. The Penumbra is the grey fuzzy circle
around the outside, the part where Shadow and Not-Shadow meet and one
fades into the other. In C# applications, I imagine that the pure area of the
code base is the Umbra, and the areas of compromise are the Penumbra. My
task is to maximize the Pure area, and minimize as much as humanly possible
the non-Pure area.
Recursion
If you don’t understand this, see: Recursion Otherwise, see: Seriously,
Recursion
Seriously, Recursion
Recursion has been around for as long as programming, pretty much. It’s a
function that calls itself in order to effect an indefinite (but hopefully not
infinite) loop. This should be familiar to anyone that’s ever written code to
traverse a folder structure, or perhaps written an efficient sorting algorithm.
A recursive function typically comes in 2 parts:
A condition, used to determine whether the function should be called
again, or whether an end-state has been reached (e.g. the value we’re
trying to calculate has been found, there are no sub-folders to explore,
etc.)
A return statement, which either returns a final value, or references the
same function again, depending on the outcome of the end-state
condition.
Here is a very simple recursive Add5:
function int AddUntil(int startValue, int endValue)
{
if(startValue == endValue)
return startValue;
else
AddUntil(startValue + 1, endValue);
}
Silly though the example above is, note that I never change the value of
either integer. Each call to the recursive function contained copies of the
original paremeters, which might sometimes be modified versions. This is
another example of Immutability - I’m not changing values in a variable, I’m
making a call to a function using a modified version of the original values.
Recursion is one of the methods Functional Programming uses as an
alternative to statements like While and ForEach. There are some
performance issues in C#, however. There is a whole chapter coming up at a
later point to discuss Recursion, Tail Recursion and Tail Call Optimised
Recusion, but for now just use it cautiously, and stick with me. All will
become clear…
Pattern Matching
In C# this is basically Switch statements with “go-faster” stripes. F# takes
the concept further, though. We’ve pretty much had this in C# for a few
versions now. The Switch expressions introduced in C# 8 introduced our
own native implementation of this concept, and the Microsoft team has been
enhancing it regularly.
It’s switching where you can change the path of execution on the type of the
object under examination, as well as its properties. It can be used to reduce a
large, complex set of nested if-statements into a few fairly concise lines. It’s
an incredible, powerful feature, and one of my favourite things.
There are many examples of this coming up in the next couple of chapters,
so skip ahead if you’re interested in seeing more about what this is all about.
Also, for those stuck using older versions of C#, there are ways of
implementing this, and I’ll show a few tips on it later.
Stateless
Object-Orientated code typically has a set of state objects, which represent a
process - either real, or virtual. These state objects are updated periodically,
to keep in sync with whatever it is they represent. Something like this, for
example:
public class DoctorWho
{
public int NumberOfStories { get; set; }
public int CurrentDoctor { get; set; }
public string CurrentDoctorActor { get; set; }
public int SeasonNumber { get; set; }
}
public class DoctorWhoRepository : IDwRepo
{
private DoctorWho State;
public DoctorWhoRepository(DoctorWho initialState)
{
this.State = initialState;
}
public void AddNewSeason(int storiesInSeason)
{
this.state.NumberOfStories += storiesInSeason;
this.SeasonNumber++;
}
public void RegenerateDoctor(string newActorName)
{
this.state.CurrentDoctor++;
this.state.CurrentDoctorActor = newActorName;
}
}
Well, forget ever doing that again if you want to do Functional Programming.
There is no concept of a central state object, or of modifying its properties,
like in the code sample, above.
Seriously? Feels like purest craziness, doesn’t it? Strictly, there is a state, but
it’s more of an emergent property of the system.
Anyone that’s ever worked with React-Redux has already been exposed to
the Functional approach to state (which was, in turn, inspired by the
Functional Programming language, Elm). In redux, the application state is an
immutable object, which isn’t updated, but instead a function is defined by
the developer that takes the old state, a command, and any required
parameters, then returns a new, updated state object based on the old one.
This process became infinitely easier in C# with the introduction of Record
types in C# 10. I’ll talk more on that later. For now though, a simple version
of how one of the repository functions might be refactored to work
functionally might be something like this:
public DoctorWho RegenerateDoctor(DoctorWho oldState,
string newActorName)
{
return new DoctorWho
{
NumberOfStories = oldState.NumberOfStories,
CurrentDoctor = oldState + 1,
CurrentDoctorActor = newActorName,
SeasonNumber = oldState.SeasonNumber
};
}
There would obviously be a difference in how this was used, outside the
repository as well. In fact, calling it a repository is probably a bit of a mistake
now. I’ll talk more about the strategies required for stateless running
later. Hopefully this is enough to get an idea of how Functional code
might work.
Students also viewed