Wednesday, May 13, 2009

Why C# is Getting Functional? Cos for LINQ, OOP is choked! (ZT)

Functional Programming stuff are creeping in into C#. Some people like it, some people confused, some people discouraged.

Why do we need to add Functional Programming stuff into C#? Cos OOP principles get choked to do one thing C# would like to do, LINQ. Other ways are needed. And it’s Functional Programming way.

Implicitly Typed Local Variable

In C# 3.0, we have the implicitly typed local variable like this:

var i = 5;

So, we don’t need to define the type like this:

int i = 5;

Don’t get it wrong, this line of code will raise an error:

var i = 5;
i = “Booyah!”;

Why? Unlike the “var” you’ve heard from Dynamically Typed Languages, in C# 3.0, once a variable is typed you can’t change the type. In the example above, i’s type is inferred from the Right Hand Side and became an “int”. Once it is typed as an “int” it stays an “int”. You can’t change the type.

This capability (type inferrencing) comes from Functional Programming. Why it is needed in C#? Cos it’s handy to do Higher Order Function (function that takes or output functions as parameter) as we don’t need to define the type, let the expression body (code at Right Hand Side) infer the type.

Then, why do we need to do Higher Order Function kind of thing? So that we can pass around code (function) just like we pass around data. In other words, code/function becomes data! Code, just like data is an expression. Hmm, “Everything is an Expression”. Another Functional stuff. How C# does it? Thru “Lambda Expressions”.

Before we get into “Lambda Expressions” I’d like you tointroduce Extension Methods first.

Extension Methods

In C# 3.0, we can add a method to a type dynamically/at runtime. We can add method to a type not at compile time. We can add method to a type even if we don’t have the source code (class) of the type. How? Thru “Extension Methods”.

See the code below:

public static void MyFunkyMethod(this string s)
{
// whatever
}

Notice the keyword “this” in the argument part. See the “string” type next to it. Now System.String would have that “MyFunkyMethod” method.

All you need to do is import the namespace where the MyFunkyMethod resides, and you can do this:

String myString = “Booyah!”;
myString.MyFunkyMethod(); // See, MyFunkyMethod is added to System.String not at compile time of the System.String.

We can achieve such thing in OOP way thru Visitor Design Patterns. But it’s more cumbersome off course. Anyway, why do we need to add “Extension Methods” capability to C#? Cos we want to add methods to existing types in C#. Why do we need to do that? Read on!

Lambda Expressions

Remember my statement above? That C# will use “Lambda Expressions” to be able to pass around code (as expression) just like data? Actually Lambda Expression is evolution of Delegate & Anonymous Type. Here’s one example:

s => {return s+1}

that can be simplified as

s => s+1

This expression says, it takes “s” as input and the body part says it returns “s+1”. I hope you can do the delegate or anonymous type of that expression. It’s trivial. My point is, yes, you can do it in delegate or anonymous type way, but “Lambda Expressions” is more neat.

LINQ, putting it all together

Now, I will put all the pieces together.

With “Extension Methods”, I can add a method let say named “Where” to types that are Collection, but not in compile time. With Lambda Expression, I can pass code as argument to that method. And in Lambda Expressions, I don’t need to define the type as it is inferred.

So, I might have a code like this:

Where(s => s.Length == 5);

It takes an expression “s => s.Length == 5” as its argument. With Extension Methods capability, I can add this “Where” method to array, collections, List, etc.

I also can do other method named “Select” that is also receive a Lambda Expression as argument and I may have code like this:

Select(s => s);

Lambda Expression “s => s” is “s => {return s}”, simply returns the argument.

Now, see this code:

string[] names = {“John Petrucci”, “David”, “John Myung”, “Mike Portnoy”, “Normy”);
IEnumerable expr = names.Where(s => s.Length == 5).Select(s => s);

Or you can do it in more aesthetic way:

IEnumerable expr = names
.Where(s => s.Length == 5)
.Select(s => s);

This expression “names.Where(s => s.Length == 5).Select(s => s);” is actually a query expression. Can you see it? It querys element of names (string) that has length equals to 5. It’s a query expression, but it’s strongly typed, and Intellisense can be used too. Not like a TSQL string “Select * from names where len(s)=’5’” that is a string. You can’t check the query syntax correctness at compile time. But in expression “names.Where(s => s.Length == 5).Select(s => s);” you can!

Then it’s up to us now to do the actual query in the “Where” and “Select” method. We can write code that simply query collections in memory, and also… yes, databases! Just like ORMs! Not just that, XML storage too. Etc.

Rely to API is not always a good thing. What if the implementation changed? What if the method name changed? API is more fragile than language keywords. So, Microsoft decided to introduce few new keywords that currently rely to the API I mentioned above.

So, the code becomes:

IEnumerable expr = from s in names where s.Length == 5 select s;

You can also write the code in more aestethic way:

IEnumerable expr = from s in names
where s.Length == 5
select s;

The new Keywords are in bold.

As any other Best Practices, if the language already have the keyword to “represent” an API, use the language keyword and not the API directly. Cos API changes more often or new/better API might come. Let the compiler choose which API to be used. Newer compiler will always choose newer/better API. So, you rely to language keyword, not API. If new or better API comes, all you need to do is recompile your code with the newer compiler. No need to REWRITE your code.

Functional Programming way is used cos OOP just simply can’t do it

Here you go! You have LINQ, a very powerful long waited capability in a programming language. You can do queries to “in memory collections”, RDBMS, XML Storage, etc, in one UNIFORM way. The elegance of LINQ can only be achieved via Functional Programming Style. You can’t achieve it by only relying to OOP.

Yes, Type Inferencing, Extension Methods and Lambda Expressions are made to support LINQ. But, since you have it in C#, you can use them for other purposes too. You can do some Functional Programming ways in C#.

I’m not saying OOP is stupid or something. It just it can’t do some stuff where other approach can do. But then OOP still do wonders in area where it can do wonders. 

So, open your mind, folks. Get over your OOP obsession. Learn all programming paradigm!

0 Comments:

Post a Comment

<< Home