la guarida de DuckMaestro

Anonymous Functions

Introduction

Knowing how to use anonymous functions (or anonymous methods) is a critical piece to have in your programming playbook. It's a great technique for quickly building up proof of concept code or first iteration code, and over the lifetime of a project save many hours of work when properly applied. Lucky for us, the "anonymous" aspect doesn't have to be mysterious.

Basics

Let's start with some examples in JavaScript (a.k.a. ECMAScript). Note that the (near) equivalent of an anonymous function in C# is the anonymous method, and I'll speak on some of the differences between the two later.

A Basic Function (JavaScript)

// a definition
function AddAndAlert(x, y) {
    var result = x + y;
    alert(result.toString());
}

Firstly, the inner logic here is probably a bad idea in practice, as it couples a data operation with a user interface operation. Disclaimer aside, this is what your basic function in JavaScript looks like.

An Anonymous Function (JavaScript)

// an expression
function(x, y) {
    var result = x + y;
    alert(result.toString());
}

What's different here? Well, the function doesn't have a name for one thing. In fact here we're looking at an expression that evaluates to a function object. This expression can be passed into other methods, or can be assigned to a variable name. For example you might decide to declare a variable fnMyFunc and assign the above expression to it.

var fnMyFunc 
    = function(x, y) {
        var result = x + y;
        alert(result.toString());
    }
;

fnMyFunc(3,7);

The last line simply calls the function, which should present "10" to the user.

What's The Point?

What we're really demonstrating here is the fact that JavaScript treats functions as first-class objects. A very common use of object-like functions is to define predicates for filtering sets or arrays. If you are familiar with SQL then you have already used predicates which are similar the conditions listed within your WHERE clauses. In JavaScript, a good example is with jQuery (a popular JavaScript library), where you can use anonymous functions as predicates to filter sets of HTML elements according to complex programmer-defined rules. Example:

var jqAllMyDivs = $("div");

var jqDivsWithMoreThanTwoChildren 
    = jqDivs
    .filter(
        function() {
            if($(this).find("*").length > 2) { return true; }
            else { return false; }
    )
;

Notice the use of an anonymous function, simply an expression that is passed into the jQuery function filter. At a conceptual level we're defining a predicate that requires an object have at least two children; but at a technical level we're defining a function that, once called, evaluates certain inner expressions to return either true or false, signalling whether or not your conditions were met. For example, if jqDivs has 12 elements, then our anonymous function is executed 12 times, once for each element. A new set is then generated containing only the elements which met our conditions.

If you're confused about some of the code there, just know that $() is a jQuery method for constructing sets using elements in an HTML document, $(this) constructs a jQuery object containing the element being inspected at that moment, and filter acts much like WHERE does in SQL.

Now, to borrow a line from everyone's favorite marketing bit ...but wait... there's more!

The Magic of Closures

Thus far, anonymous functions have been just fine and dandy. They give us some flexibility in how we package up our logic, and also allow us to neatly group related chunks of logic near to each other. But where the true power and convenience lie is in closures.

Simply put, a closure is internally managed, and contains access to all the variables needed for an anonymous function to execute. Let's modify our first example and see how a closure let's us break some preconceived rules.

function AddAndAlert(x, y, delay) {
    var result = x + y;

    window.setTimeout(
        function() 
        { 
            // notify user
            alert(result.toString()); 
        }, 
        delay
    );
}

// add 4 and 9, and notify the user
// one second later.
AddAndAlert(4, 9, 1000);

Now, if you have a keen eye (or some C++ background) your bat senses should be freaking out about now. We're declaring a local variable result, defining a function that relies on result, scheduling our function for later execution, but immediately leave scope of AddAndAlert. Won't the value of result be undefined (in the C++ sense) when fnNotifyUser executes? The answer no -- in fact the JavaScript runtime has prepared a closure for us that contains a reference to result. This closure is implicitly bundled with fnNotifyUser so that when it is finally executed, it will still have access to the data stored in result as of the time AddAndAlert returns. Furthermore, result as a variable remains unique to each call to AddAndAlert, resulting in no inconsistancies or race conditions.

This is a very powerful feature of the language, especially when needing to build logic that executes in a deferred manner, or logic with complex dependencies that would otherwise require you explicitely package up data for passage to other areas of your code. Any or all local variables in your "outer" function can at any time be utilized by your "inner" anonymous functions without any extra work by the programmer.

Be warned though, there are some "interesting" behaviors that become apparent when relying on closures and loops. I'll cover these gotchas, including some work-arounds, in a follow up post.

C# Anonymous Methods

Now that we know in JavaScript how anonymous functions are built and how closures work, let's take a look at the equivalent in C#.

The good news is that C# fully supports all the concepts covered thus far. The biggest differences are in the syntax and in the fact that C# is a strongly-typed language. Let's revisit our previous examples side-by-side with JavaScript and C#.

A Basic Function (JavaScript)

// a definition
function AddAndAlert(x, y) {
    var result = x + y;
    alert(result.toString());
}

A Basic Method (C#)

// a definition
void AddAndAlert(int x, int y)
{
    int result = x + y;
    Console.Write(result.ToString());
}

An Anonymous Function (JavaScript)

// an expression
function(x, y) {
    var result = x + y;
    alert(result.toString());
}

An Anonymous Method (C#)

// an expression
delegate(int x, int y)
{
    int result = x + y;
    Console.Write(result.ToString());
}

The first thing you'll notice is the "delegate" keyword, which reminds us that the underlying base type that our expression evaluates to is a Delegate. You can think of the Delegate type as being a function pointer combined with a context pointer.

As you will find out, in more complicated situations it's easy to get slowed down by explicit typing in C# when using delegates. C# 3.0 features a great deal of type inference though, some built-in generic delegate types, and lambda expressions. Each of these is beyond the scope of this article but save a great deal of time. For now let's wrap up with our last JavaScript example as written in C#.

Deferred Execution w/Use of Closure (JavaScript)

function AddAndAlert(x, y, delay) {
    var result = x + y;

    window.setTimeout(
        function() 
        {
            // notify user
            alert(result.toString()); 
        }, 
        delay
    );
}

// add 4 and 9, and notify the user
// one second later.
AddAndAlert(4, 9, 1000);

Deferred Execution w/Use of Closure (C#)

void AddAndAlert(int x, int y, TimeSpan delay)
{
    int result = x + y;
    ThreadPool.QueueUserWorkItem(
        delegate(object state) 
        { 
            // very bad! for consistent example only
            Thread.Sleep(delay); 

            // notify user
            Console.Write(result.ToString()); 
        }
    );
}

void MyStartingCode()
{
    AddAndAlert(4, 9, new TimeSpan(0, 0, 1));
}

Notice the similarities -- the logic contained in our anonymous delegate is not executed until a later time and until outside the scope of AddAndAlert. However, because a closure is maintained for us with our anonymous method, our inner logic will have access to result with the correct value.

I like to use the word "magic", especially when describing C# anonymous methods, because there is some trickery that happens under-the-hood to make this behavior work correctly in C#. (more).

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License except where otherwise noted.


comments powered by Disqus