CSC/ECE 517 Fall 2010/ch1 1b gb: Difference between revisions
No edit summary |
No edit summary |
||
Line 360: | Line 360: | ||
<pre>c = lambda{|a,b| puts a +b}</pre> | <pre>c = lambda{|a,b| puts a +b}</pre> | ||
<pre>array.iterate!(method(:square))</pre> | <pre>array.iterate!(method(:square))</pre> | ||
||<pre> new Outerclass({innerclass})</pre> || <pre>function outerf{ cube_inner(s){.... return inners}return cube_inner}</pre> || | ||<pre> new Outerclass({innerclass})</pre> || <pre>function outerf{ cube_inner(s) | ||
{.... return inners}return cube_inner}</pre> || | |||
<pre>public: bool operator()(int a) {...</pre> | <pre>public: bool operator()(int a) {...</pre> | ||
<pre>for_each(v.begin(), v.end(), [&evenCount] (int n)..</pre> | <pre>for_each(v.begin(), v.end(), [&evenCount] (int n)..</pre> |
Revision as of 01:08, 9 September 2010
What is a Closure?
Before diving into the differences of closures in Ruby viz a viz other languages, lets look at some traditional definitions of the same, and some history of closures to better understand the concept at hand.
A closure is a first-class function with free variables that are bound in the lexical environment. Closures:Wikipedia
For the layman, lets break up the technical sounding definition into easier terms. Basically a first class function is something that can be passed onto as arguments to other functions i.e. it can behave like any other object or variables. A closure has its own variables with last as long as the scope of the closure and are independent of any other scope. (We will see later, how this is of importance)
Another author of a Blog:A definition for closures defines a closure as
A closure is a function that captures the bindings of free variables in its lexical context.
It’s evident that this follows what we have written earlier.
Going further into layman’s terms, we could say that a closure is a kind of a ‘hidden function’ (similar construct in C, later) which is used by programmers in various languages to provide enhanced functionality in their programs/
Another writer states
A closure is a property associated with functions; when a function manipulates input and produces output which holds the features and characteristics of the input, then the function is said to possess (we should say 'satisfy' instead of 'possess') the closure property.Closures Definition
Landin is credited with introducing the term closure while referring to a lambda expression whose ‘Open Bindings’ or ‘free variables’ that have been bound ‘closed’ in a lexical environment resulting in a closed expression or ‘closure’.Closures:Wikipedia
Since we are here to compare all types of closures with Ruby, lets look into the closure definition of the Ruby creator. Yukihiro Matsumoto defines closure as a Nameless function object and goes on to say that A closure object has code to run, the executable, and state around the code, the scope. Blocks and Closures in Ruby
Closures in Ruby
The concept of closures is quite analogous to first-class functions i.e. it facilitate encapsulation of a certain behavior for example loop abstraction. Moving a step further it also grants access to the context which means you get to capture the environment in which the closure is based irrespective of the scope of the context.
Ruby offers – not one – but three different ways of creating closures. They are blocks , procs and lambdas. The syntax varies in a trifling way than the other however each exhibits a distinct behavior.
Let us go over all of them one by one
Blocks
The simplest way to define a block would be calling it a ‘nameless’ entity which is nothing but a group of statements. Also unlike functions you don’t have to name the block in the methods when it is called. Consider the following lines of code:
Set = [2,3,5,7,11] Set.collect! do |n| n+1 end puts Set.inspect # => [3,4,6,8,12]
It is apparent from the code that the block interacts with the array elements and squares them. Its important to note that blocks are not reusable. But their importance lies in the fact that they provide abstraction as well as transactional control in some cases.
Procs
Procs can be said to be the super-set of blocks. The difference between procs and blocks is that is since proc is called using an argument instead of using the keyword ‘yield’ like blocks, the code is reusable. Hence, one can conclude - a block is a proc which cannot be saved i.e. it can be used only once. Lets see an example to understand it better.
class Array def iterate!(code) self.each_with_index do |n, i| self[i] = code.call(n) end end end array_1 = [1, 2, 3, 4] array_2 = [2, 3, 4, 5] square = Proc.new do |n| n ** 2 end array_1.iterate!(square) puts array_1.inspect # => [1, 4, 9, 16]
As we can see the proc has been invoked twice for two different set of elements which confirms the re-usability of procs. Hence, its safe to assume Procs as functions in RUBY.
Lambda
Lambda - Lambdas , more commonly known as ‘anonymous functions’ in other languages similar to procs. But unlike procs, lambdas check the number of arguments passed . Consider the following piece of code:
c = lambda{|a,b| puts a +b} c.call(2,3) c.call(2)
The second statement prints 5 as the output. At the same time the third gives rise to an ArgumentError Another noticeable difference would be they way return is dealt with by Procs and lambda. The return from Procs is a return from the method in which it is called whereas a return from lambda goes back to the calling function. One can also say that the return of a proc overrides the calling methods return however return from lambda does not.
Method
RUBY provides one more way of implementing closures with the help of RUBY’s method method.Closure by Method Following the previous example used for procs , the only modification in the code is the way ‘square’ function is applied to the array.
def square(n) n**2 end array = [1,2,3,4] array.iterate!(method(:square))
Here, the square method is converted to a method object and then passed to the function. Using a method object is conceptually same as using lambda however lambdas do not have names but methods do.
Closures in Languages Other than Ruby
Java
RUBY has some direct language support which facilitates the use of closures.JAVA on the other hand supports closures indirectly in the form of anonymous classes or inner classes. Anonymous inner classes are often used in event handling for implementing adapter class. Using inner classes one can gain access to all the attributes and private data of the outer class which resembles closures.
Let us consider the following example:
Public class test{ Private JFrame f; Private JTextField txt; Class myclass extends MouseMotionAdapter{ Public void mouseDragged(MouseEvent e){ String s =” X co-ordinate : “ +e.getX() + “Y co-ordinate: “ +e.getY(); txt.setText(s); } Public void launchFrame(){ … … f.addMouseMotionListener(new myclass()); }
As we can see, in the function launchFrame() the object of inner class is created using keyword new. The object is used to call the function mouseDragged() which gives access the text field which is declared in outer class thus implementing a closure.
Another way of implementing the same code is including the entire class definition within the scope of an expression i.e.
f.addMouseMotionListener(new MouseMotionAdapter() { Public void mouseDragged(MouseEvent e){ String s =” X co-ordinate : “ +e.getX() + “Y co-ordinate: “ +e.getY(); txt.setText(s); }});
Closures are officially the newest addition to Java 7, the latest version of Java Closures in Java 7. The previous mentioned partial closures in Java are highly simplified with the help of this new functionality that has been proposed. The above example can be written this as:
f.addMouseMotionListener(#(MouseEvent e){ String s =” X co-ordinate : “ +e.getX() + “Y co-ordinate: “ +e.getY(); txt.setText(s); });
JavaScript
Closures in JavaScript help us exploit the private variables and methods while creating the JavaScript objects. This is achieved by writing nested functions and making a call to the outer function and ‘freeze’ the inner function by providing it an external reference. Closures in Javascript The following example will clarify the technique:
function cube_outer(a,b) { var ex2 = 2; var ex3 = 3; function cube_inner(s){ if(s == “plus”) var result = Math.pow(a,ex3)+3*(Math.pow(a,ex2))*b + 3*(Math.pow(b,ex2))*a + Math.pow(b,ex3); else if(s == “minus”) var result = Math.pow(a,ex3)-3*(Math.pow(a,ex2))*b + 3*(Math.pow(b,ex2))*a - Math.pow(b,ex3); return result; } return cube_inner ; } var cube =cube_outer(3,4); console.log(‘cube is = “ + cube(plus));
Unlike RUBY , JavaScript lacks the syntax to use closures in a varied manner. Nevertheless, it can be used as a remedy for quite a few problems faced in JavaScript. The infamous looping problem in JavaScript can be solved successfully using closures. Consider the following piece of code.
function addButton() { var buttons = new Array[25] ; for(var i = 0;i< 25;i++){ Buttons[i] = document.createElement(“Button “ + i); Buttons[i].onclick = function () {alert(“Button” + i);}; }}
In here, 25 buttons are created and when each button is clicked upon an alert event indicating the correct button number is suppose to take place. Since all the elements in the array instead of having the value of ‘i’ have reference to the same variable i(local variables are not copied but kept by reference) , all buttons on clicking display ‘24’.
This problem can be taken care of by taking the snapshot of ‘i’ each time the loop is executed. Hence, we can write a function which and invoke it in the loop.
function getvalue(x){ return function(){alert (“Button” + x);}; } function addButton() {for(var i =0;i<25;i++) { buttons[i] = document.createElement(“Button “ + i); buttons[i].onclick = getvalue(i); } }
Thus, for every value of i a new execution context is formed using a closure and the value of i is retained. This is a good demonstration of the power of closures to capture the lexical context at a certain point in the program flow.
C++
Overloading ()
In C++, closures are achieved by means of a feature called functors or function objects. C++ uses the traditional OO approach of operator overloading to achieve closures. The operator () is overloaded to pass on a function instead of a function pointer to another function, behaving as a object. Here is an example
class square_class { public: bool operator()(int a) { return a*a; } }; template <class SquaringFunctor> void square_ints(int* begin_items, int num_items, SquaringFunctor c); int main() { int items[] = {4, 3, 1, 2}; square_class functor; square_ints(items, sizeof(items)/sizeof(int), functor); }
In the above code, the square_ints function has the squaring code called inside it using the overloaded () operator.
Lambda Expressions
Lambda expressions like the ones used in Ruby have been recently discussed to and ratified by the C++ standards committee. Such features were already avaible in compilers such as Microsoft VC++. Lambda Expressions in VC++ The above squaring function can be written in Lambda expression in C++ as
Vector <int> v; for (int i = 0; i < 4; ++i) { v.push_back(i); } for_each(v.begin(), v.end(), [&square] (int n) //Lambda Expression here embedded in For each { n= n*n; });
C#
In C#, closures are implemented using delegates. Delegates are type-safe function pointers used by the .net framework. They are used to call a method and optionally an object to call the method on. Viz a viz closures, delegates allow us to call upon a method in its own lexical environment and can be treated like the object having the scope in which it was declared. .NET 2.0 onwards, these delegates are implemented as follows
We can take the example of the list of integers which need to be squared.
public static Func<int> Square() { Func<int,> sqr = delegate(int item) { return item*item; }; return sqr; } } ... var v = Square(); foreach(int i in intarr) { console.writeline(v(i)); }
C
Closures in C were not implemented from the beginning due to its compiled nature. Recently, Apple introduced support for closures in their version of the C Compiler included with Mac OS 10.6. This feature uses the operator '^' to define blocks or collection of code which can be used for passing the whole of it to other functions. It works much like function pointers in C. Blocks for C,Closures in Mac OS 10.6 Here is an example.
square = ^ int (int a) { return a * a; }; r = square(i);
Perl
Closures in perl can be achieved by making a reference to a function. This reference can then be used to call the function whenever needed.Perl Documentation Taking our squaring example, we can write it in perl as
sub raise_to_power{ my $Power = shift return sub { my $sub_arg = shift; return $sub_arg ** $power; }; } my $func = raise_to_power(2); print func->(2);
Python
Closures in Python are implemented using Lambda or Nested functions.
Lambda
Lambda in Python is much like Ruby itself. However this method has a shortcoming that the result of this has to be a single expression and not anything more. So it can be used for only simple rudimentary closures. Carrying on with our previous examples, we can write
def square(int) return lambda i:i*i, int
Nested Functions
Another way to write closures in Python is to use nested functions, meaning writing functions inside functions. Our squaring example can be written in this scheme as
def power(integer): def calulate(input): nonlocal integer input = input**integer return input return calculate f = power(2) print(f(2), f(3), f(4))
There is a caveat however, to closures in Python. All variables inside a closure in Python are read only.
All closures at a glance
Ruby | Java | JavaScript | C++ | |
---|---|---|---|---|
Construct | Blocks,Procs,Lambda,Method | Anonymous Inner Classes | Nested Functions | Overloading(),Lambda Expressions |
Example | do |n| ... end square = Proc.new do |n|... array_1.iterate!(square) c = lambda{|a,b| puts a +b} array.iterate!(method(:square)) |
new Outerclass({innerclass}) |
function outerf{ cube_inner(s) {.... return inners}return cube_inner} |
public: bool operator()(int a) {... for_each(v.begin(), v.end(), [&evenCount] (int n).. |
Comment | Most Versatile of all closure providing languages | Java closures are very verbose | Overloading () provides a reference to the anonymous function |