View the whole series:
This is part one in an n part series about the functional programming aspects in C# 3.0. Now you may have read other blog posts by other people describing these features, but the difference between this series of articles and those other posts is that I am *not* a functional programmer. In one or two college courses I may have had to write a Lisp program or two, but I have long since banished that from my mind. So this whole process will hopefully be a learning experience for me as well as for you.
So, lets start with the basics…Wikipedia defines functional programming as:
“a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast with the imperative programming style that emphasizes changes in state.”
Snoooooooooooore. Essentially what this is saying is that in purely functional programming every variable is immutable (once it has been set, it cannot be changed) and everything is a parameter to, or result of, a function.
So, lets have an example. Here is a factorial function in Scheme, which is a command dialect of Lisp, which is actually the second oldest programming language in existence. Just in case you were thinking that this functional programming stuff was all new and fancy, it is actually quite old! (this factorial function was also borrowed from Wikipedia):
(define (fact n)
(if (= n 0) 1
(* n (fact (- n 1)))))
Now, this probably looks pretty strange to someone who has never seen a Scheme program, so lets break it down. First the left parentheses “(” starts the beginning of a function. So, we have started with a “define” function, which is actually a function that lets us define a function (How nice of it). Then, you will see “(fact n)” and this is saying that this function is called “fact” and will take one parameter, which is “n”. (Keep in mind that types are implicit in Scheme) Next we have “(if” which is the start of the “if” function. I told you, *everything* is a function. Everything.
Now, the next part is going to look really strange for those who have never seen prefix notation (also called Polish notation) which is simply when you put operators before operands. What you are probably used to see in most languages is infix notation, where the operators come between the operands. So, in Lisp “1 + 2” would look like “+ 1 2”. So “(if (= n 0)” simply translates into C# as “if (n == 0)”. Then the “1” following this if statement is what is returned if n is 0, and then “(* n (fact (- n 1)))))” represents the “else clause” of the if function. If we break this down we will see that it takes n and multiplies it against a recursive call to the “fact” function that is taking “n – 1” as a parameter. Now was that so hard? Yes, yes it was. 🙂
So now that we have taken forever to explain one simple list function, you are probably getting ready to click the back button on your browser. Well don’t! The hard stuff is over! Kinda. This next part is what separates the boys from the men (or the girls from the women, if you prefer), and you may leave a crying, sobbing baby.
So, why I am showing you all of this? Well, because it is important to get a little tiny bit of background. The factorial function above could be implemented just as easily in C# and we don’t even need any special functional features to do it. I just wanted you to see what a functional language looks like before I start beating you about the head with closures.
So, what is a closure? Lets start again by looking at a definition from Wikipedia (trust me, this is all going to help you understand the C# 3.0 language features, I’m not trying to be a textbook here):
“A closure is a function that is evaluated in an environment containing one or more bound variables.”
Hmmmm. That is about as clear as milk. Lets try to clear this up a bit with the stereotypical closure example…
Sidenote:
Some people have claimed that C# does not support true closures because of the fact that the variables actually bind to the variables inside of the anonymous method or lambda, but this is actually exactly why C# *does* support closures.
//declare us a little delegate
delegate void WriteMe();
static void Main(string[] args)
{
//we first set s to "output1"
string s = "output1";
//assign our anonymous method
WriteMe w = delegate()
{
System.Console.WriteLine(s);
};
//reset s to "output2"
s = "output2";
//voila, it prints out "output2"
w();
}
Here we have a chunk of code that will actually compile in C# 2.0. We are declaring a delegate and then assigning an anonymous method to it. An anonymous method is just a method that does not have a name. Since it does not have a name, you cannot call it without a direct reference. While this may sound limiting, it actually has a number of uses. So, as you can see from the comments in the code, we are assigning “s” a value, then we assign the anonymous method, then we reassign “s” and then we call our delegate. The delegate prints out the second value of “s” because it is “bound” to it. Instead of it getting the value of “s” at the time it was declared it gets a reference to s.
Sidenote:
In C# 2.0 one of the most common uses is with predicates where anonymous methods provided a somewhat succinct syntax for passing a predicate to another method. As anyone who tried to use predicates in VB.net can attest to! (since VB.net does not support anonymous methods)
And that is pretty much it! A closure simply allows us to declare a method that is bound to the variables around it. It lets us do some really powerful things that we will discuss in a future post.
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.
Delegates (function pointers in general) are a substitute to have lambda functions.
Yep, I cover that a lot more thoroughly in the second part of this post.
Cool, but this was the easy stuff. Bring on the currying! 🙂
P.S. If you can post about Memoization, that would be cool too. It’s a really great functional technique for keeping stuff in memory without having to worry about maintenance.
Yeah, part 2 steps it up a bit with lambdas, but next I’m going to get into Higher Order functions and then get into Currying, Memoization, Function Composition, etc… my head will hurt (and hopefully yours too) by the time we are done. This is as much a learning experience for me as it is for you guys.