CSC/ECE 517 Fall 2012/ch1 1w32 cm
CLOSURES FOR STATICALLY TYPED LANGUAGES
INTRODUCTION
A closure is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables) of that function.[1] A closure—unlike a plain function pointer—allows a function to access those non-local variables even when invoked outside of its immediate lexical scope.Closures can typically be treated like any other programming language objects, e.g. they can be stored in variables, passed to functions, and so on. The best way to understand closures is to think about an example in Scheme.
(define f (lambda (x) (lambda (y) (+ x y))))
This is the simplest non-trivial example using closures. Here f is a function of one argument (x). When you call it, you pass it a single number as an argument, which gets bound to x. The return value from calling the function is another function which takes one argument (lambda (y) ...) This new function always adds x to its input (whichever x was passed when the function was created). [3]
Importance of Closures
The uses of closures:
1. They make the code clear and readable. Shorter code has lesser bugs and can be debugged easily. Example in java: The following is a code in Java programming without closures
public interface Block<T> { void invoke(T arg); } public class Utils { public static <T> void forEach(Iterable<T> seq, Block<T> fct) { for (T elm : seq) fct.invoke(elm); } } public class Test { public static void main(String[] args) { List<Integer> nums = Arrays.asList(1,2,3); Block<Integer> print = new Block<Integer>() { public void invoke(Integer arg) { System.out.println(arg); } }; Utils.forEach(nums,print); } }
The example is admittedly contrived and extremely simple, but consider it: how often in Java do you find yourself implementing an interface and passing the implementation to a method for execution? We can think of three immediate examples:
Runnable and Callable, which we pass to threads or thread pools for asynchronous execution. Callback interfaces such as ActionListener, which we register for future execution in case a certain event occurs. Comparator, which we pass to a TreeMap for maintaining its sorting order.
In all these cases we use an interface, providing some functionality as an implementation of the interface. We then pass the functionality to a method for immediate or delayed, synchronous or asynchronous execution. Closures would simplify this process by allowing a more concise syntax, thereby eliminating some of Java's verbosity. Beyond allowing more concise and readable Java source code, closures would add some functionality completely new to Java, such as custom control structures.
2. Closures allow you to create units of work, which each have their own copy of the stack, and don't step on each others toes as a result. So you can pass these units around like they are values, when in actual fact they contain a whole stack of values (pun intended), and executable code to perform some operation.
3.Code like the following, which is common in functional languages, can be parallelized for you, without you needing to create a pool of worker threads and hand off the closure to them:
results = map(closure, inputs, [0..numElements-1]); In these languages, closures take away the pain of declaring a new function somewhere for short pieces of code.
4. Because closures delay evaluation i.e., they do not "do" anything until they are called so they can be used to define control structures. For example, all Smalltalk's standard control structures, including branches (if/then/else) and loops (while and for), are defined using objects whose methods accept closures. Users can easily define their own control structures also. In languages that allow assignment, multiple functions can be produced that close over the same environment, enabling them to communicate privately by altering that environment.