Declarative programming can often be a simpler, more concise way to describe the behaviour of a software program than imperative programming.
I have been an admirer of declarative aspects of programming ever since I
started writing SQL queries. We always do our best to write code that
is easier to read and maintain. Declarative style is one of the proven
ways to write clean code. LINQ
is an excellent example of declarative style programming that enables
the developers to simply state what they want to do. When I am learning higher order functions in Haskell,
I have found the interrelationship between the higher order functions
and the LINQ. It really made me think in a different way to solve a
problem. Through this blog post I would like to share my experiments on higher order functions in C#. Let me start with a very simple requirement.
Write a program to print the even numbers present in the given n numbers
The code implementation is fairly straight forward below (all code snippets can be enlarged by clicking on them)
Let me add a twist to the code by adding two more requirements.
Modify the program implemented above to print odd numbers and multiples of four present in the given n numbers
To be honest, If I had encountered this requirements before I had
learned Higher Order Functions my implementation would be the following.
If you look at the above implementation with a critical eye, you can
find a potential candidate of duplication. Let me explain the common
pattern that is being used in the implemented PrintXXXX functions.
1. For each number in the numbers enumerable
a. Decide whether the number should be printed or not (Deciding)
b. Print the number if it is passes the above decision (Doing)
All
the three functions iterate over the numbers enumerable and print the
numbers. The only thing that actually differentiates the functions is
deciding which numbers will be printed.
Now the question is how can we eliminate this duplication?
It’s
where higher order functions come into picture. If we move the deciding
part of the function away from its implementation then we can easily
achieve it. Here we go! The brand new implementation of Print would be:
In the new implementation we have just isolated the deciding part of
the function from its implementation and parameterized it as a function
delegate that takes an integer as its input and returns a Boolean value.
In the client code (Main function) we are actually just calling the
print function and declaratively telling it to print only those numbers that satisfy the given condition. As we separated the deciding part
from the actual implementation, we can easily accommodate any future
requirements like “Printing multiples of five, printing only single digit numbers” by declaratively calling the Print function as you can see below:
Cool.. Isn’t it ? Let me complicate the things little more. What would
you do if you want to call this Print method across different classes? A
notorious option would be creating a Utility class with the Print method and calling it from the other classes. We can also solve these using Extension methods which result in clean readable code like this:
So far, so good. We have started with a single function and then we
added two more, then eliminated the duplication using Higher Order
functions and finally we have made the code readable by using an extension
method.
Okay. Now “I want to print the strings that start with ‘s’ in the given n strings ”. Pardon me for complicating things, I will stop after this one.
It is almost logically similar to what we have done so far. Instead of
numbers here, it is a string. How can we put it into action?. By using Generics. We can easily achieve this by modifying the extension method to support generic types as below
That’s it. Now you are free to play with all sorts of logic you want.
You can play with different set of conditions to print the elements or
even use different collections of your custom classes. And
all can be done declaratively!!
Now its time to reveal to the interrelationship that exists between LINQ
and the higher order functions. All the LINQ methods are actually using
these Print extension methods under the hood
and it makes life easy for the developer while still allowing them to work
declaratively.
Parallel Class,
a new addition in C# 4.0, also uses higher order functions and enables
the developer to say “Hey CLR, I wanna run these methods parallel”.
Awesome! No new thread creation and it's not verbose.
Summary
Declarative Programming is a powerful tool. It creates more readable,
cleaner code and also saves the possibility of logical mistakes in
similar algorithms. That means fewer mistakes now and in the
future.
Comments