In the next article, we would look at the characteristics of Functional Programming. This article assumes the user has basic knowledge of writing simple C# programs and understands delegates.
Functional Programming (FP) in simple words is "Declarative Programming". That means FP does not deal with how to do (lines of code for achieving some functionality) but speaks about what to do. Microsoft introduced FP support with the release of .NET 3.5. LINQ and Lambda expression are one of the implementations of FP.
Let us say we have a customers object and we want to determine a customer based on the city "London", in normal programming. To accomplish that we need to loop through each object and check if the customer.city == "London". But the same thing can be accomplished using the Lambda Expression without writing more lines of code (in fact a one-line statement) as below:
-
- public class Customers
- {
- public int CustomerId { get; set; }
- public string CustomerName { get; set; }
- public string City { get; set; }
- }
-
- List<Customers> customers =new List<Customers>
- {
- new Customers(){CustomerId = 1,City = "Delhi",CustomerName = "Praveen"},
- new Customers(){CustomerId = 1,City = "London",CustomerName = "Raheem"},
- new Customers(){CustomerId = 1,City = "Malvern",CustomerName = "Pradeep"}
- };
-
- var findCustomerAtLondon = customers.Where(c => c.City == "London");
All of us know how to write a delegate. Simply a delegate is a strongly typed function pointer which refers to a method that has the same signature as the delegate.
A simple example of a delegate is as follows:
-
-
- delegate int MyDelegate(int a, int b);
- public class Program
- {
-
-
-
-
-
-
- public static int Sum(int a, int b)
- {
- return a + b;
- }
-
-
-
-
- public static void Main(string[] args)
- {
-
-
-
- MyDelegate myDelegate = Sum;
- int @delegate = myDelegate(5, 6);
- Console.WriteLine(@delegate);
- Console.Read();
- }
Figure 1: Sum of two numbers
So you can use strongly type delegates for referring to the methods if the signatures match. C# has another way of doing this; by using generic functional types (Functional Programming). It is represented as Func<T, Result>.
We can replace the above delegate instance with the following code:
- Func<int, int, int> f = Sum;
- int @delegate = f(5, 6);
Syntax of Func in detail
A function type is represented as Func<T1, T2…TN, Output> where T1...TN can be of any type that is input to the function and Output is the return type of the function. Wherever we use delegates, those can be replaced with function types.
We can also write the above code as the following using a lambda expression:
- Func<int, int, int> f = (a, b) => a + b;
- int @delegate = f(5, 6);
So, you should be able to refer to a method and its type can be used as a variable and it can return a type too.
Other than Func, we have two more generic function types. They are Action and Predicate.
An Action simply is a function type that returns nothing i.e. void.
A Predicate is a function type that returns Boolean.
So you can represent an Action as:
Action<T1...TN>
Equivalent to Func<T1...TN, Void>. Do not try to create with this syntax as the compiler will give an error as void is not a return type.
Predicate can be represented as below
Predicate<T>
Equivalent to Func<T, bool>. You can try this and it works.
Action and Predicate in detail
Let us try to understand how we can use Action by modifying our previous code
Declare a class variable with Action type
Here the Action type takes an integer value and performs some functionality based on which function it is referring to.
private static readonly Action<int> write = Console.WriteLine;
We have defined a variable of type Action and it is pointing to the method WriteLine of the Console class. Since WriteLine does not return any value we can make Action to refer to the method.
Now you simply replace the code for Console.WriteLine with write variable.
- write(@delegate);
- Console.Read();
Now let us see how we can use the Predicate.
- string name = "Ravi";
- Action<bool> print = Console.WriteLine;
- Predicate<string> myPredicate = (a) => (a.equals("Raju"));
- bool predicate = myPredicate(name);
- print(predicate);
Here I have declared a string variable and then created another Action type which takes a Boolean value and prints it using Console.writeLine method. I have declared a Predicate Type and this refers to the lambda expression that checks if the value is equal to "Raju". This would return a false value.
Output of Predicate and Func using Action is as below
I am providing some more examples of Func, Action, and Predicate for a better understanding
We have the following functions available. Now try to identify what function type is to be used for each method.
- static string SayHello(string userName)
- {
- return string.Format("{0} says Hello to you", userName);
- }
- static void PrintMyName(string myName)
- {
- Console.WriteLine("My name is {0}",myName);
- }
- static bool CheckIfTwoStringsAreEqual(string a, string b)
- {
- return (a.Equals(b));
- }
- static bool IsGreaterThan5(int a)
- {
- return a > 5;
- }
The first method takes a string parameter and returns a string type. So, according to what we understood it must be referred by Func type.
- Func<string, string> hello = SayHello;
- string s = hello("Venu");
The second method takes a string parameter and returns void and so, it must be referred by Action Type.
- Action<string> print = PrintMyName;
- print("Venu");
The third method takes two string parameters and returns a Boolean type. So, it can be referred by Func type.
- Func<string, string,bool> check = CheckIfTwoStringsAreEqual;
- bool b = check("abc", "abc");
The fourth method takes only one int parameter and returns bool and so we can use Predicate for this.
- Predicate<int> predicate = IsGreaterThan5;
- bool predicate1 = predicate(10);
It can be replaced by Func type.
- Func<int, bool> func = IsGreaterThan5;
- bool func1 = func(5);
Important points to note (Some extra information)
A Func type or Action can take only up to 4 parameters and Predicate can always take only one parameter. If you try to add extra parameters other than the supported compiler gives you an error message. According to best practices, any delegate should refer to a method that does not take more than 4 parameters. If any method is taking more than 4, you might have to refactor it.
The following are according to .NET 3.5.
If you are using .NET 4, then you will see the supported number of parameters as below
Predicate still takes one parameter only.
Action takes 16 parameters.
- public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
-
- public delegate bool Predicate<in T>(T obj);
Func takes 16 parameters
- delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
Also observe that if you click on "go to declaration", it shows that Action is a delegate. So, internally the generic function types are also delegates.
Conclusion
The main intention of the article is to get familiar with 3 generic function types: Func, Action, and Predicate. In the next article, we will try to understand the concept of Functional Programming in more detail.
Hope you liked this article.