Thursday, 9 August 2012

Recursive anonymous methods/functions

At first thought the idea of a recursive anonymous function can seem rather unfeasible, how can it call itself if it has no name? Well, in the old times, the way to achieve this in JavaScript was by means of arguments.callee. Its use has been deprecated, and the recommended solution is naming function expressions, you know:

var f1 = function f1(){
};

That's fine, but if for the sake of knowledge we wanted to use an anonymous function, we still can do it, thanks to closures. A function can trap itself, (I've already used this technique before, so we could just write:

var printNTimes = function(txt, n) {
   if (n > 0){
    console.log(n + " - " + txt);
    printNTimes(txt, --n);
   }
  };
printNTimes("Asturies", 3);

Our anonymous function is trapping in its closure the printNTimes variable, that is pointing to the function itself. Thinking in terms of the [[scope]] object and Executions context, the implementation seems clear.

Could we do the same in C# with Anonymous Methods and Closures?
Yes, we can, we already saw in this sample what a brilliant beast the C# compiler is in order to create the oddly named classes underlying the closure mechanism in .Net. There's a small detail to take into account, though:

Action<string, int> printNTimes = (txt, n) => {
   if (n > 0)
   {
    Console.WriteLine(n.ToString() + " - " + txt);
    printNTimes(txt, --n);
   }
  };
  printNTimes("Asturies", 3);

The compiler will spit this error when going through the code above:

Error CS0165: Use of undefined local variable...

The fix is simple, we just need to declare the variable in a previous statement

Action<string, int> printNTimes = null;
printNTimes = (txt, n) => {
   if (n > 0)
   {
    Console.WriteLine(n.ToString() + " - " + txt);
    printNTimes(txt, --n);
   }
  };
  printNTimes("Asturies", 3);

If we think about the structure generated by the compiler, it's interesting. We have a class with a method containing the code for the anonymous method, and a data field that points to a delegate created for that method (and of course, that method is using that data field), so all in all, we have a cute recursive structure

Watchout! Testing this on Linux I've seen that under the Mono compiler (gmcs) we don't need the extra declaration, the first case compiles fine (and also under the Windows Mono compiler)

No comments:

Post a Comment