What is Closure

As there is a growing interest in dynamic languages, more people are running into a programming concept called Closures or Blocks. People from a C/C++/Java/C# language background don't have closures and as a result aren't sure what they are. Here's a brief explanation, those who have done a decent amount of programming in languages that have them won't find this interesting.

Closures have been around for a long time. I ran into them properly for the first time in Smalltalk where they're called Blocks. Lisp uses them heavily. They're also present in the Ruby scripting language - and are a major reason why many rubyists like using Ruby for scripting.

Essentially a closure is a block of code that can be passed as an argument to a function call. I'll illustrate this with a simple example. Imagine I have a list of employee objects and I want a list of those employees who are managers, which I determine with an IsManager property. Using C#, I'd probably write it like this.

public static IList Managers(IList emps) {

    IList result = new ArrayList();

    foreach(Employee e in emps)

      if (e.IsManager) result.Add(e);

    return result;

  }

  In a language that has Closures, in this case Ruby, I'd write this.

def managers(emps)

  return emps.select {|e| e.isManager}

end

  

Essentially select is a method defined on the Ruby collection class. It takes a block of code, a closure, as an argument. In ruby you write that block of code between curlies (not the only way). If the block of code takes any arguments you declare those between the vertical bars. What select does is iterate through the input array, executes the block of code with each element, and returns an array of those elements for which the block evaluated as true.

Now if you're a C programmer you probably think "I could do that with a function pointer", if you're a Java programmer you probably think "I could do that with an anonymous inner class", a C#er would consider a delegate. These mechanisms are similar to closures, but there are two telling differences.

The first one is a formal difference, closures can refer to variables visible at the time they were defined. Consider this method

def highPaid(emps)

  threshold = 150

  return emps.select {|e| e.salary > threshold}

end

  Notice that the code in the select block is referring to a local variable defined in the enclosing method. Many of the alternatives to closures in languages that don't have real closures can't do that. Closures allow you to do even more interesting stuff. Consider this function.

def paidMore(amount)

  return Proc.new {|e| e.salary > amount}

end

  This function returns a closure, indeed it returns a closure whose behavior depends on the argument sent into it. I can create such a function with and assign it to a variable.

highPaid = paidMore(150)

  The variable highPaid contains a block of code (called a Proc in Ruby) that will return whether a tested object has a salary greater than 150. I might use it like this.

john = Employee.new

john.salary = 200

print highPaid.call(john)

  

The expression highPaid.call(john) calls the e.salary > amount code I defined earlier, with the amount variable in that code bound the to the 150 I passed in when I created the proc object. Even if that 150 value went out of scope when I issue the print call, the binding still remains.

So the first crucial point about closures is that they are a block of code plus the bindings to the environment they came from. This is the formal thing that sets closures apart from function pointers and similar techniques.(Java's anonymous inner classes can access locals - but only if they are final.)

The second difference is less of a defined formal difference, but is just as important, if not more so in practice. Languages that support closures allow you to define them with very little syntax. While this might not seem an important point, I believe it's crucial - it's the key to make it natural to use them frequently. Look at Lisp, Smalltalk, or Ruby code and you'll see closures all over the place - much more frequently used than the similar structures in other languages. The ability to bind to local variables is part of that, but I think the biggest reason is that the notation to use them is simple and clear.

A good case in point is what happened when ex-Smalltalkers started in Java. Initially many people, including me, experimented with using anonymous inner classes to do many of things that we'd done with blocks in smalltalk. But the resulting code was just too messy and ugly so we gave up.

Like any term in software there is a lot of blur about the exact definition of closure. Some people say that the term only applies to an actual value that includes bindings from its environment, such as the value returned byhighPaid. Others use the term 'closure' to refer to a programming construct that has the ability to bind to its environment. This debate, an example of theTypeInstanceHomonym, is usually carried out with the politeness and lack of pedantry that our profession is known for.

I use closures a lot in Ruby, but I don't tend to create Procs and pass them around. Most of the time my use of closures is based aroundCollectionClosureMethods similar to the select method I showed earlier. Another common use is the 'execute around method', such as when processing a file.

File.open(filename) {|f| doSomethingWithFile(f)}

  

Here the open method opens the file, executes the supplied block, and then closes it. This can be a very handy idiom for things like transactions (remember to commit or rollback) or indeed anything where you have to remember to do something at the end. I use this extensively in my xml transformation routines.

Such use of closures is actually much less than what people in the Lisp and functional programming worlds do. But even with my limited uses I miss them a lot when programming in languages without them. They are one of those things that seem minor when you first come across them, but you quickly grow to like them.

Other languages: C# 3.0 | C# 2.0 | Python | Boo | Lisp | JavaScript

Neal Gafter has an excellent posting on the history of closures. Vadim Nasardinov led me to this interesting tidbit of history of closures in Java from Guy Steele.

 

 

 

 

你可能感兴趣的:(closure)