How to Write Functional Code in C#: An Example by Zoran Horvat @zoranh75
C# is a multiparadigm language. Among others, it allows us to write procedural
or objectoriented code, but it also supports fullblown functional coding. In
this article, we will see what benefits we can get from writing functional code
in C#. We will see what it means to write functional code and how we can
accomplish that using standard C# syntax.
In this article we will demonstrate functional approach to one simple example,
which comes from practice. The first part of the article will deal with actual
implementation, which is running in production right now, as a matter of fact.
After that, we will start refactoring the solution to a much more flexible one.
The final product will be a class that is completely designed with respect to
functional programming paradigm.
Problem Statement
Consider a problem of calculating a control digit in some document number.
Control digits are used to minimize impact of human errors. Suppose that
documents are accepted by clerks and that these numbers sometimes experience
changes caused by human error. By inadvertently changing just one digit in the
document number, we can cause costly consequences. The situation would be
significantly worse if that particular number has already been assigned to a
different document.
Correcting the error would first require to understand which document has been
entered with the wrong number. This may involve both document holders to appear
with their papers in order to figure which one got the incorrect printout. Then
additional evidence might be required to decide which of the two apparently
valid documents is the faulty one and needs to be invalidated. Now the
invalidation comes. It doesn't mean just to tear the document in pieces, but
also to annul its consequences. Other documents may have been produced in the
meanwhile, referring to this one as their source. The situation becomes
increasingly bad if other documents produced legal or financial effects based
on a document that is about to be declared void.
To minimize all that mess, document numbers often contain a control digit. This
digit typically appears at the end of the number and it is calculated from
digits that precede it. Normally, number consists of decimal digits 0 thru 9
only, and so is another decimal digit used as control digit. Result is that if
one of the preceding digits has been changed, the control digit would
immediately indicate that there is the problem, because control digit would be
different. If only one digit has been modified, control digit would definitely
indicate the problem. But if two or more digits have been changed, then their
combined effect could sometimes be that the same control digit is produced by
pure coincidence. Having ten possible values for the control digit at hand, it
turns out that single control digit will detect 100% of mistakes made on a
single digit, as well as 90% of mistakes made on more than one digit
simultaneously. Also note that mistakes made on control digit count as well.
Here is one algorithm applied to calculate control digit. This algorithm is
actually in use in real world. It is used to calculate control digit for an
insurance policy numbers issued by one particular organization that joins
several insurance companies. The document number is typed manually so many
times, and the idea to put in a control digit was probably the right decision.
Policy number, excluding the control digit, is nine digits long. It only
consists of decimal digits 0 thru 9. The tenth digit would be the control digit
and it would be appended at the end to form a complete policy number. Control
digit is calculated in three steps. The first step is to sum up all the
preceding digits. But, there is one additional requirement: every other digit
should be multiplied by three before being added to the sum.
Take policy number 123456789 as an example. The first step in calculating the
control digit would then be to sum up the digits, while at the same time
honoring the request to triple every other digit. So the sum is 1 + 3*2 + 3 +
3*4 + 5 + 3*6 + 7 + 3*8 + 9 = 85.
The next step is to take modulo 11 of this number: 85 mod 11 = 8. The third
step is applied only when the result of previous step is 10. In that case
control digit value should be 1. Otherwise, take the result obtained as the
control digit and append it to the insurance policy number.
Before producing the code, there was one more nuisance about this whole task.
The function had to be implemented in TSQL. Here we are still talking about a
real project for the real customer. Actual client of the stored procedure that
would calculate the control digit would be another SQL Server stored procedure.
Any idea to write a good old C# function was out before it came to the picture.
Anyway, as you will see, stored procedure implementation will serve as a
fabulous prelude to solving the same problem functionally.
Implementation as Stored Procedure
Below is the stored procedure which implements the requirements literally. The
stored procedure expects nine characters on input and produces an integer which
is the control digit for the given trimmed insurance policy number.
CREATE DATABASE Insurance
GO
USE Insurance
CREATE PROCEDURE CalculateControlDigit @policyNumber CHAR(9)
AS
BEGIN
DECLARE @controlDigit INT = 0
DECLARE @currentDigit INT
DECLARE @i INT = 1
DECLARE @sum INT = 0
WHILE @i <= 9
BEGIN
SET @currentDigit = CAST(SUBSTRING(@policyNumber, @i, 1) AS INT)
IF @i % 2 = 0
SET @sum = @sum + 3 * @currentDigit
ELSE
SET @sum = @sum + @currentDigit
SET @i = @i + 1
END
SET @controlDigit = @sum % 11
IF @controlDigit > 9
SET @controlDigit = 1
SELECT @controlDigit
END
GO
Let's try this stored procedure:
EXEC CalculateControlDigit '123456789'
When called with this argument, the procedure returns value 8, as expected.
The whole idea about calculating the control digit is to avoid common mistakes.
There are some typical mistakes that people make when typing numbers. Most
frequent mistake is to move a finger to the left or to the right of the target
key, producing a digit which is by one less or by one greater than desired.
Another typical mistake occurs on numeric keypad and that is to miss a row.
This causes a digit which is by 3 greater or less than desired. Finally, one
more mistake that commonly occurs in practice is to swap places of two digits
in the number. Let’s see how this algorithm copes with these two mistakes.
EXEC CalculateControlDigit '123556789'
This time, the stored procedure returns value 0. By comparing this control
digit with actual control digit from the whole insurance policy number, we can
figure that the number was mistyped.
Another mistake would be to increase or decrease one digit by 3:
EXEC CalculateControlDigit '123453789'
Once again, this has caused the control digit to change, this time producing
value 1 instead of 8.
And, one more example for the end – swapping two digits:
EXEC CalculateControlDigit '124356789'
Thanks to having to multiply one of the two digits by factor of three, new
control digit value has changed. It is 6, instead of 8.
We conclude that stored procedure works fine and that the algorithm really
protects us from the three most common mistakes. After this step, we will start
improving the solution. At first we will keep the stored procedure in use, but
try to write it in a little bit better way. After that, we will pretend that
there is no hard requirement to implement the solution as stored procedure and
we will move the code to C#. This will let us apply functional concepts to the
same problem.
Improving the Procedure
The first step in improving existing stored procedure code is to ask the proper
question – what is wrong with the code? One thing that annoys me is branching.
If statements complicate control flow and make it hard to read and to
understand.
In the solution above there are two if statements. One is there to control
multiplication factor for every digit separately. Another is near the end of
the stored procedure and it deals with result 10 by converting it to actual
result 1.
The first if statement can easily be eliminated by introducing another variable
– multiplicative factor:
CREATE PROCEDURE CalculateControlDigit @policyNumber CHAR(9)
AS
BEGIN
DECLARE @controlDigit INT = 0
DECLARE @currentDigit INT
DECLARE @i INT = 1
DECLARE @sum INT = 0
DECLARE @factor INT = 1
WHILE @i <= 9
BEGIN
SET @currentDigit = CAST(SUBSTRING(@policyNumber, @i, 1) AS INT)
SET @sum = @sum + @factor * @currentDigit
SET @factor = 4  @factor
SET @i = @i + 1
END
SET @controlDigit = @sum % 11
IF @controlDigit > 9
SET @controlDigit = 1
SELECT @controlDigit
END
GO
Look at the loop now. It has obviously become much simpler than before. It is
much easier to understand what it does when there is no ifthenelse statement
to obscure view. This time it is obvious that every digit is multiplied by a
factor and added to the sum. Multiplicative factors applied to digits obviously
form a sequence looking like 1, 3, 1, 3, 1, 3, and so on.
Let’s see the second if statement now. This statement jumps in when modulo
operation returns value 10. That value is translated to value 1, while all
other values are left intact. Can we figure any better method of doing the same
thing? Actually, yes, we can. If we consider all possible results of the modulo
operation to be twodigit numbers, all of them having a leading zero except
number 10, then we can transform the if statement into operation of summing up
the two digits in the resulting number. Here is the modified code:
CREATE PROCEDURE CalculateControlDigit @policyNumber CHAR(9)
AS
BEGIN
DECLARE @controlDigit INT = 0
DECLARE @currentDigit INT
DECLARE @i INT = 1
DECLARE @sum INT = 0
DECLARE @factor INT = 1
WHILE @i <= 9
BEGIN
SET @currentDigit = CAST(SUBSTRING(@policyNumber, @i, 1) AS INT)
SET @sum = @sum + @factor * @currentDigit
SET @factor = 4  @factor
SET @i = @i + 1
END
SET @controlDigit = @sum % 11
SET @controlDigit = (@controlDigit / 10) + (@controlDigit % 10)
SELECT @sum, @controlDigit
END
GO
Stored procedure is now relieved from branching code. The only remaining part
that is actually branching is the while loop. Obviously TransactSQL is not the
best place to try removing the while loop, so let’s step into C# right now and
continue coding there.
Implementing Procedure in C#
In this section we will produce the first C# implementation of the function
that calculates the control digit from a given insurance policy number. You
might be annoyed by the section title – implementing procedure in C#. Having
stored procedure left behind, we should now be dealing with “real code”, I mean
objectoriented code, right? Well, not so fast. As it will soon become
apparent, the first implementation of this function in C# will be no different
from SQL stored procedure, which really is a pity.
Let’s see what this function looks like when turned into C#:
static int CalculateControlDigit(string number)
{
int sum = 0;
int factor = 1;
for (int i = 0; i < number.Length; i++)
{
int currentDigit = number[i]  '0';
sum += factor * currentDigit;
factor = 4  factor;
}
int controlDigit = sum % 11;
controlDigit = (controlDigit 10) + (controlDigit % 10);
return controlDigit;
}
This function is literally copied from TransactSQL. And it looks like that, to
be honest. This kind of code has nothing to do with higherlevel
objectoriented programming language like C#. So let’s start changing this
function in order to make something better.
First change that we will make is to remove the string argument. It may have
been a valid requirement in the database implementation, but now that we are
dealing with the strongly typed language we can easily constrain input to
integer numbers. Due to length of the insurance policy number (ten digits,
including the control digit), we decide to use 64bit unsigned integers. But
this change requires us to implement splitting the number into its digits:
static int CalculateControlDigit(UInt64 number)
{
int sum = 0;
int factor = 1;
int[] digits = new int[9];
for (int i = 0; i < 9; i++)
{
digits[8  i] = (int)(number % 10);
number = 10;
}
for (int i = 0; i < digits.Length; i++)
{
sum += factor * digits[i];
factor = 4  factor;
}
int controlDigit = sum % 11;
controlDigit = (controlDigit 10) + (controlDigit % 10);
return controlDigit;
}
The function has actually become longer, but that is due to inability to split
the number into digits using builtin methods. Nevertheless, we can easily move
that ugly piece of code into a separate method and be done with it. What
attracts attention right now is that the factor can easily be calculated in
every iteration of the loop. There is no need to keep it memorized:
static int[] ToDigits(UInt64 number)
{
int[] digits = new int[9];
for (int i = 0; i < 9; i++)
{
digits[8  i] = (int)(number % 10);
number = 10;
}
return digits;
}
static int CalculateControlDigit(UInt64 number)
{
int sum = 0;
int[] digits = ToDigits(number);
for (int i = 0; i < digits.Length; i++)
sum += (1 + 2 * (i % 2)) * digits[i];
int controlDigit = sum % 11;
controlDigit = (controlDigit 10) + (controlDigit % 10);
return controlDigit;
}
The function is shrinking again. That is good. Multiplicative factor has been
replaced by a fairly cryptic piece of arithmetic. But that was done with a
reason, and the reason is to remove the last piece of nonlinear control flow
from this function. The for loop is the last part of the function which doesn’t
just execute and move on. Instead, this loop keeps running in circles until all
digits have been exhausted.
This is the point where functional programming begins. In the next section we
will transform this procedural solution into functional solution.
Functional Approach
In order to remove the for loop, we decide to use LINQ to Objects. Extension
methods provided by this component of the .NET Framework implement the foreach
loop internally. By relying to those methods, we remove the need to iterate
through the array on our end – that will be the job of extension methods.
Here is the modified function which utilizes LINQ to Objects:
static int CalculateControlDigit(UInt64 number)
{
int[] digits = ToDigits(number);
int sum =
digits
.Select((digit, index) => (1 + 2 * (index % 2)) * digit)
.Sum();
int controlDigit = sum % 11;
controlDigit = (controlDigit 10) + (controlDigit % 10);
return controlDigit;
}
From this implementation it becomes obvious why it was so important to remove
the multiplicative factor variable and to calculate the factor in every
iteration of the loop. In this implementation, we are using the Select
extension method overload which tells us the index of each digit visited in the
process. This lets us calculate the multiplicative factor in place.
This solution begins to look like functional. But it’s still not done. If you
look at the function, it consists of several segments. The first segment splits
the number into digits. The second segment calculates the sum. The third
segment, which is the last one, calculates the control digit from the sum.
This sequence of steps looks procedural. We can modify the code to make it look
more functional. As the first step, observe that ToDigits method can be
implemented more elegantly:
static IEnumerable<int> DigitsFromLowest(UInt64 number)
{
do
{
yield return (int)(number % 10);
number = 10;
}
while (number > 0);
}
This almost trivial method returns a collection of digits of a given number,
starting from the lowest digit. Now we can use this method to implement the
CalculateControlDigit function without ever using the ToDigits function. On a
related note, ToDigits function made an assumption about how many significant
digits there are in the number. DigitsFromLowest, on the other hand, returns
the collection of all digits no matter how many of them there are. Let’s put
this new function into motion:
static int CalculateControlDigit(UInt64 number)
{
int sum =
DigitsFromLowest(number)
.Reverse()
.Select((digit, index) => (1 + 2 * (index % 2)) * digit)
.Sum();
int controlDigit = sum % 11;
controlDigit = (controlDigit 10) + (controlDigit % 10);
return controlDigit;
}
As you can see, the function has become even more compact than before. Note
that we had to use the Reverse extension method to reverse order of digits.
This is because sequence of multiplicative factors assumes that highest digit
is taken first. We could, of course, start from the lowest digit and adapt the
sequence of multiplicative factors to that case. But then, the function would
be sensitive to total length of the insurance policy number. Suppose that
12digit long policy numbers are added in the future – sequence of
multiplicative factors starting from the least significant digit would then
have to be reverted. In this way, with the Reverse method used, actual sequence
of digits passed to the Select method is from the most significant digit
towards least significant digit.
At this moment, the function that converts number to a collection of digits
looks a little odd. It is defined in the same class that calculates the control
digit, but it really doesn’t belong there. It would be better if the number
itself could tell its digits. And that is possible, thanks to the extension
methods. We can modify the code to work in the same way as any of the LINQ
extension methods. Here is the class that accommodates an extension method to
unsigned 64bit integer numbers which lets them tell their digits out:
static class NumberExtensions
{
public static IEnumerable<int> DigitsFromLowest(this UInt64 number)
{
do
{
yield return (int)(number % 10);
number = 10;
}
while (number > 0);
}
}
Right now, this class only defines this single extension method. But that is
sufficient for us to simplify our control digit calculator another bit:
static int CalculateControlDigit(UInt64 number)
{
int sum =
number
.DigitsFromLowest()
.Reverse()
.Select((digit, index) => (1 + 2 * (index % 2)) * digit)
.Sum();
int controlDigit = sum % 11;
controlDigit = (controlDigit 10) + (controlDigit % 10);
return controlDigit;
}
This time, the method is asking the number to split itself into digits. Then it
sums up the digits according to rules. After this change, only the end of the
function remains – part that calculates the control digit out of the sum. It
doesn’t take much to turn this piece of code into functional code as well.
Let’s define two more extension methods, this time for int data type:
static class NumberExtensions
{
...
public static int Modulo(this int number, int divisor)
{
return number % divisor;
}
public static IEnumerable<int> DigitsFromLowest(this int number)
{
return ((UInt64)number).DigitsFromLowest();
}
}
The first method adds operation Modulo to int data type. The second operation
lets us split signed integer into digits. How do these two methods help us
complete the control digit calculation? Here is the answer:
static int CalculateControlDigit(UInt64 number)
{
return
number
.DigitsFromLowest()
.Reverse()
.Select((digit, index) => (1 + 2 * (index % 2)) * digit)
.Sum()
.Modulo(11)
.DigitsFromLowest()
.Sum();
}
This is almost final form of the control digit calculation, this time written
as a functional program. It is possible to improve this code a bit by adding
more convenient extension methods:
static class NumberExtensions
{
...
public static IEnumerable<int> DigitsFromHighest(this UInt64 number)
{
return number.DigitsFromLowest().Reverse();
}
...
public static int SumDigits(this int number)
{
return number.DigitsFromLowest().Sum();
}
}
Now the code becomes even easier to read:
static int CalculateControlDigit(UInt64 number)
{
return
number
.DigitsFromHighest()
.Select((digit, index) => (1 + 2 * (index % 2)) * digit)
.Sum()
.Modulo(11)
.SumDigits();
}
There are two elements in this function that make it harder to understand. The
first nuisance is the cryptic formula which calculates the sequence of
multiplication factors 1, 3, 1, 3, etc. The other one is the last
transformation which leaves all singledigit inputs intact, while input value
10 is transformed to output 1. These two transformations are purely arithmetic
and they emerged directly from the requirements. But they do not read the same
as requirements specified them. That could cause certain level of discomfort
when reading this code. A little makeup could help make this first formula
easier to read. Also, in both cases, a short comment could easily clarify the
situation. This is the situation when programming language – C# in this case –
doesn’t seem to be expressive enough to make these two transformations easier
to read. Anyway, we can get away with a few words of comments, and a little bit
of refactoring:
static int CalculateControlDigit(UInt64 number)
{
int factor = 3;
return
number
.DigitsFromHighest()
.Select(digit =>
{
factor = 4  factor;
return factor * digit;
})
.Sum()
.Modulo(11)
.SumDigits();
}
This implementation is based on a closure, which is another functional term.
Variable factor is captured from the enclosing scope and used inside the
delegate passed to the Select method. Note that this anonymous delegate is
changing the value of the factor in every call.
Last statement can be made a little easier to understand by adding another
specialized extension method:
static class NumberExtensions
{
...
public static int ChangeIfEqualTo(this int number, int equalTo, int setTo)
{
if (number == equalTo)
return setTo;
return number;
}
}
...
static int CalculateControlDigit(UInt64 number)
{
int factor = 3;
return
number
.DigitsFromHighest()
.Select(digit =>
{
factor = 4  factor;
return factor * digit;
})
.Sum()
.Modulo(11)
.ChangeIfEqualTo(10, 1);
}
This last step may be a little stretched. Personally, I would prefer to leave
the previous implementation that sums up the digits, and just add a short
comment beside it. Anyway, the code now reads the same as requirements in plain
English, to the letter. Let me demonstrate it. Here is what we get if we try to
read this method literally.
To calculate control digit of a number take digits of that number, starting
from the most significant digit, multiply every other digit by factor 3, sum up
the results, and take modulo 11 of the result. That will be the control digit,
unless it is equal to 10. In this case, use value 1 instead.
This paragraph sublimates a very important aspect of functional programming.
The code says what it does. There are no mental mappings to ifthenelse
statements or for loops. The most important quality of this way of coding is
readability. We can read this function like a sentence.
Next thing that I plan to show you in this article is how to make value out of
this function. Function itself is nice, but it has a limited value. Real value
comes with reusability, and in the world of objectoriented programming, reuse
comes with objects. Therefore, the time has come to put this function into a
real class.
Combining Functional and ObjectOriented Programming
Now that we have a nice function for calculating the control digit for an
insurance policy number, we can wrap that function into a nice class:
class PolicyNumber
{
public UInt64 Value { get; private set; }
private PolicyNumber(UInt64 number)
{
if (!ValidateNumberWithControlDigit(number))
throw new System.ArgumentException("Control digit validation failed.");
this.Value = number;
}
public static PolicyNumber FromNumberWithoutControlDigit (UInt64 number)
{
int controlDigit = CalculateControlDigit(number);
return FromNumberAndControlDigit(number, controlDigit);
}
public static PolicyNumber FromNumberAndControlDigit(UInt64 number, int controlDigit)
{
return FromNumberWithControlDigit(10 * number + (UInt64)controlDigit);
}
public static PolicyNumber FromNumberWithControlDigit(UInt64 number)
{
return new PolicyNumber(number);
}
private static int CalculateControlDigit(UInt64 number)
{
int factor = 3;
return
number
.DigitsFromHighest()
.Select(digit =>
{
factor = 4  factor;
return factor * digit;
})
.Sum()
.Modulo(11)
.ChangeIfEqualTo(10, 1);
}
private static bool ValidateNumberWithControlDigit(UInt64 number)
{
int controlDigit = (int)(number % 10);
UInt64 rawNumber = number 10;
int correctControlDigit = CalculateControlDigit(rawNumber);
return controlDigit == correctControlDigit;
}
}
This class is only used to contain actual policy number. Class design follows
the rule that complete validation is done in the constructor. Once constructor
execution ends and new object is created, the object is guaranteed to be
correct. In particular, it means that control digit is correct. This rule has
one important consequence in practical coding. We don’t have to ask whether any
PolicyNumber instance is valid. If the object exists, it is valid. It is as
hard as that.
Note that the only constructor of this class is declared private. Instances can
only be created through one of the three static methods – these are the factory
methods. Each of them can create a policy number under different circumstances.
The first one receives a number without control digit. This method calculates
control digit and attaches it to the number. Note that this particular method
will never fail because it doesn’t have any control digit to validate. The
second factory method receives a number and a control digit. The last factory
method receives a complete number, which includes the control digit. These
three methods let us construct policy number in any situation we might find
ourselves in.
One more quality of the PolicyNumber is that the underlying number cannot
change once the object has been constructed. PolicyNumber is an immutable
class. It implements the Value Object design pattern, if you like it that way.
To emphasize this fact, but also to protect ourselves from unintentional
changes made to underlying policy number, we could let the compiler help us
keep the object immutable:
class PolicyNumber
{
private readonly UInt64 value;
public UInt64 Value { get { return value; } }
...
}
In this way, underlying value must be set through the constructor. After that
point there is no way to change it during the lifetime of the object. In order
to change the policy number, we must construct a new object with the new
underlying value.
But this is not all. Suppose that we have a class that represents insurance
policy. Policy must be given a number at some point. Let’s simplify matters and
say that the number is assigned when policy is instantiated:
class Policy
{
public Policy(PolicyNumber number)
{
Console.WriteLine("Issuing a policy: {0:0000000000}", number.Value);
}
}
We don’t need anything more than this at the moment. Now we want to be able to
issue several insurance policies in a row, but in such a way that they occupy
subsequent numbers. In order to support that, we could introduce another
factory method which creates policy number which comes just after a given
policy number:
class PolicyNumber
{
...
public static PolicyNumber FromPreceding(PolicyNumber number)
{
UInt64 withoutControlDigit = number.value 10;
UInt64 followerWithoutControlDigit = withoutControlDigit + 1;
return PolicyNumber.FromNumberWithoutControlDigit(followerWithoutControlDigit);
}
...
}
Now we can build a sequence of policy numbers:
class PolicyNumber
{
...
public static IEnumerable<PolicyNumber> Sequence()
{
PolicyNumber current = PolicyNumber.FromNumberWithoutControlDigit(0);
while (true)
{
current = PolicyNumber.FromPreceding(current);
yield return current;
}
}
...
}
This way of combining objects into a sequence is sometimes funny. But at its
core, it is functional. The Sequence method produces an infinite sequence of
insurance policy numbers. Do you know how we can issue ten insurance policies
in one batch now? Here it is:
Policy[] policies =
PolicyNumber.Sequence()
.Take(10)
.Select(number => new Policy(number))
.ToArray();
This statement builds a batch of ten insurance policies. Remember that policy
class used to print assigned number when instantiated. Here is what we get on
the console when this statement is executed:
Issuing a policy: 0000000011
Issuing a policy: 0000000022
Issuing a policy: 0000000033
Issuing a policy: 0000000044
Issuing a policy: 0000000055
Issuing a policy: 0000000066
Issuing a policy: 0000000077
Issuing a policy: 0000000088
Issuing a policy: 0000000099
Issuing a policy: 0000000101
Or, alternatively, suppose that we want to persist the last issued policy
number and then to continue from the following number tomorrow. Here is the
overloaded Sequence method which supports starting from a specific policy
number:
class PolicyNumber
{
...
public static IEnumerable<PolicyNumber> Sequence()
{
return Sequence(PolicyNumber.FromNumberWithoutControlDigit(0));
}
public static IEnumerable<PolicyNumber> Sequence(PolicyNumber lastIssued)
{
PolicyNumber current = lastIssued;
while (true)
{
current = PolicyNumber.FromPreceding(current);
yield return current;
}
}
...
}
Now we can issue a batch of ten policies with numbers that are following the
last one issued before:
Policy[] policies =
PolicyNumber.Sequence(PolicyNumber.FromNumberWithoutControlDigit(293742814UL))
.Take(10)
.Select(number => new Policy(number))
.ToArray();
This time, the sequence of policies looks a bit differently:
Issuing a policy: 2937428152
Issuing a policy: 2937428163
Issuing a policy: 2937428174
Issuing a policy: 2937428185
Issuing a policy: 2937428196
Issuing a policy: 2937428200
Issuing a policy: 2937428211
Issuing a policy: 2937428222
Issuing a policy: 2937428233
Issuing a policy: 2937428244
This is the functional way of thinking about policy numbers. Policy number now
behaves like any other number in the world – it only has a bit of validation
that is intrinsic to it and it carries that logic with it wherever it goes.
Summary
In this article we have demonstrated that functions, although coded in
objectoriented language such C# definitely is, are nothing more than
datadriven procedures. We want to step out of the procedural mentality and to
produce code which is fully objectoriented. But it is not an easy task to do.
Functional extensions to C# are an easy and elegant way to turn everything into
objects. Any operation can be implemented by asking several objects to
transform certain state. As long as objects are providing convenient functions
that can transform their state into another state, we are happy to chain such
operations into a sequence of transformations that lead us to the final result.
When code is formatted in this way, it can be read as a sentence in natural
language.
Another benefit from functional programming is that control constructs, such as
loops and branching, can be entirely removed. These constructs are embedded in
utility methods, such as LINQ extension methods that are applying a
transformation to every element in the collection. Once this paradigm is fully
accepted, a totally new way of thinking about code begins to emerge. It is no
longer important to understand precise sequence of steps to perform an
operation. That would return us back to procedural thinking. Instead, it
becomes important to understand sequence of transformations applied to elements
of a collection. These transformations can change input data into a single
value as desired.
See also:
Published: Dec 11, 2014; Modified: May 28, 2015
ZORAN HORVAT Zoran is software architect dedicated to clean design and CTO in a growing software company. Since 2014 Zoran is an author at Pluralsight where he is preparing a series of courses on objectoriented and functional design, design patterns, writing unit and integration tests and applying methods to improve code design and longterm maintainability. Follow him on Twitter @zoranh75 to receive updates and links to new articles. Watch Zoran's video courses at pluralsight.com (requires registration): Making Your C# Code More ObjectOriented This course will help leverage your conceptual understanding to produce proper objectoriented code, where objects will completely replace procedural code for the sake of flexibility and maintainability. More... Advanced Defensive Programming Techniques This course will lead you step by step through the process of developing defensive design practices, which can substitute common defensive coding, for the better of software design and implementation. More... Tactical Design Patterns in .NET: Creating Objects This course sheds light on issues that arise when implementing creational design patterns and then provides practical solutions that will make our code easier to write and more stable when running. More... Tactical Design Patterns in .NET: Managing Responsibilities Applying a design pattern to a realworld problem is not as straightforward as literature implicitly tells us. It is a more engaged process. This course gives an insight to tactical decisions we need to make when applying design patterns that have to do with separating and implementing class responsibilities. More... Tactical Design Patterns in .NET: Control Flow Improve your skills in writing simpler and safer code by applying coding practices and design patterns that are affecting control flow. More... Writing Highly Maintainable Unit Tests This course will teach you how to develop maintainable and sustainable tests as your production code grows and develops. More... Improving Testability Through Design This course tackles the issues of designing a complex application so that it can be covered with high quality tests. More... Share this article
