CSC/ECE 517 Fall 2010/ch1 1b gb: Difference between revisions
No edit summary |
No edit summary |
||
(41 intermediate revisions by 2 users not shown) | |||
Line 2: | Line 2: | ||
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. | 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. | ||
:<blockquote>''A closure is a first-class function with free variables that are bound in the lexical environment.'' [http://en.wikipedia.org/wiki/Closure_%28computer_science%29 Closures:Wikipedia]</blockquote> | :<blockquote>''A closure is a first-class function with free variables that are bound in the lexical environment.'' [http://en.wikipedia.org/wiki/Closure_%28computer_science%29 Closures:Wikipedia<sup>1</sup>]</blockquote> | ||
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) | 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:[http://gafter.blogspot.com/2007/01/definition-of-closures.html A definition for closures] defines a closure as | Another author of a Blog:[http://gafter.blogspot.com/2007/01/definition-of-closures.html A definition for closures<sup>2</sup>] defines a closure as | ||
:<blockquote>''A closure is a function that captures the bindings of free variables in its lexical context.''</blockquote> | :<blockquote>''A closure is a function that captures the bindings of free variables in its lexical context.''</blockquote> | ||
Line 12: | Line 12: | ||
It’s evident that this follows what we have written earlier. | It’s evident that this follows what we have written earlier. | ||
Another writer states | Another writer states | ||
:<blockquote>''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.''[http://linuxgazette.net/112/ramankutty.html Closures Definition]</blockquote> | :<blockquote>''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.''[http://linuxgazette.net/112/ramankutty.html Closures Definition<sup>3</sup>]</blockquote> | ||
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 | |||
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’''.[http://en.wikipedia.org/wiki/Closure_%28computer_science%29 Closures:Wikipedia<sup>1</sup>] | |||
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. [http://www.artima.com/intv/closures2.html Blocks and Closures in Ruby] | |||
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. [http://www.artima.com/intv/closures2.html Blocks and Closures in Ruby<sup>4</sup>] | |||
Line 31: | Line 32: | ||
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. | 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 | Ruby offers – not one – but four different ways of creating closures. They are blocks , procs ,lambdas and methods. 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 | Let us go over all of them one by one | ||
Line 41: | Line 42: | ||
Consider the following lines of code: | Consider the following lines of code: | ||
<pre> | <pre> | ||
class Array | |||
def traverse! | |||
self.each_with_index do |z, i| | |||
self[i] = yield(z) | |||
end | end | ||
end | |||
# => [ | end | ||
odd_val = [11, 9, 7, 5] | |||
odd_val.traverse! do |z| | |||
z - 1 | |||
end | |||
puts odd_val | |||
# => [10,8,6,4] | |||
</pre> | </pre> | ||
It is apparent from the code that the block interacts with the array elements and | It is apparent from the code that the block interacts with the array elements and decrements each element by 1. It is important to note that the block is automatically converted to proc object and there is no explicit call to it. The way to use it is using ‘yield’ keyword. Hence, blocks are not reusable i.e it the same block cannot be called for a different array. But their importance lies in the fact that they provide abstraction as well as transactional control in some cases. | ||
=== Procs === | === Procs === | ||
Line 55: | Line 67: | ||
<pre> | <pre> | ||
class Array | class Array | ||
def traverse!(obj) | |||
self.each_with_index do |z, i| | |||
self[i] = obj.call(z) | |||
end | |||
end | end | ||
end | |||
Procsarray = [2,4,5,6] | |||
Procsarray2 = [6,5,4,3] | |||
decrement = Proc.new do |z| | |||
z - 1 | |||
end | |||
Procsarray.traverse!(decrement) | |||
Procsarray2.traverse!(decrement) | |||
puts Procsarray.inspect | |||
puts Procsarray2.inspect | |||
output: | |||
[1, 3, 4, 5] | |||
[5, 4, 3, 2] | |||
</pre> | </pre> | ||
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. | 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. | ||
Line 79: | Line 96: | ||
=== 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: | |||
<pre> | <pre> | ||
c = lambda{|a,b| puts a +b} | c = lambda{|a,b| puts a +b} | ||
Line 85: | Line 102: | ||
c.call(2) | c.call(2) | ||
</pre> | </pre> | ||
The second statement prints 5 as the output. At the same time | The second statement prints 5 as the output. At the same time third statement 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. | 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 === | === Method === | ||
RUBY provides one more way of implementing closures with the help of RUBY’s method method.[http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-and-methods/ Closure by Method] | RUBY provides one more way of implementing closures with the help of RUBY’s method method.[http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-and-methods/ Closure by Method<sup>5</sup>] | ||
Following the previous example used for procs , the only modification in the code is the way ‘square’ function is applied to the array. | Following the previous example used for procs , the only modification in the code is the way ‘square’ function is applied to the array. | ||
<pre> | <pre> | ||
def | def decrement(z) | ||
z - 1 | |||
end | end | ||
array = [ | array = [3,4,5,6] | ||
array. | array.traverse!(method(:decrement)) | ||
</pre> | </pre> | ||
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. | 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 == | == Closures in Languages Other than Ruby == | ||
Line 155: | Line 173: | ||
</pre> | </pre> | ||
Closures are officially the newest addition to Java 7, the latest version of Java [http://www.experts-exchange.com/Programming/Languages/Java/A_2690-Closures-in-Java-7-does-a-new-era-start-for-the-language.html 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: | Closures are officially the newest addition to Java 7, the latest version of Java [http://www.experts-exchange.com/Programming/Languages/Java/A_2690-Closures-in-Java-7-does-a-new-era-start-for-the-language.html Closures in Java 7<sup>6</sup>]. 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: | ||
<pre> | <pre> | ||
Line 171: | Line 189: | ||
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 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. | ||
[http://jessecravens.com/04092008/understanding-javascript-closures Closures in Javascript] | [http://jessecravens.com/04092008/understanding-javascript-closures Closures in Javascript<sup>7</sup>] | ||
The following example will clarify the technique: | The following example will clarify the technique: | ||
<pre> | <pre> | ||
Line 193: | Line 211: | ||
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. | 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. | ||
<pre> | <pre> | ||
function addButton() | function addButton() { | ||
{ | var buttons = new Array[5] ; | ||
for(var i = 0;i< 5;i++){ | |||
var buttons = new Array[ | |||
for(var i = 0;i< | |||
Buttons[i].onclick = function () {alert(“Button” + i);}; | Buttons[i].onclick = function () {alert(“Button” + i);}; | ||
}} | |||
</pre> | </pre> | ||
In here, | In here, 5 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 ‘4’. | ||
This problem can be taken care of by taking the snapshot of ‘i’ each time the loop is executed. | 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. | Hence, we can write a function which and invoke it in the loop. | ||
<pre> | <pre> | ||
function getvalue(x){ | function getvalue(x){ | ||
return function(){alert (“Button” + x);}; | |||
} | } | ||
function addButton() | |||
{for(var i =0;i<5;i++) { | |||
Buttons[i].onclick = getvalue(i); | |||
}} | |||
</pre> | </pre> | ||
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. | 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++ === | === C++ === | ||
Line 245: | Line 257: | ||
==== Lambda Expressions ==== | ==== 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++. [http://msdn.microsoft.com/en-us/library/dd293608%28VS.100%29.aspx Lambda Expressions in VC++] | 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++. [http://msdn.microsoft.com/en-us/library/dd293608%28VS.100%29.aspx Lambda Expressions in VC++<sup>8</sup>] | ||
The above squaring function can be written in Lambda expression in C++ as | The above squaring function can be written in Lambda expression in C++ as | ||
<pre> | <pre> | ||
Line 267: | Line 279: | ||
We can take the example of the list of integers which need to be squared. | We can take the example of the list of integers which need to be squared. | ||
<pre> | <pre> | ||
public static | public static func<int> Square() | ||
{ | { | ||
func<int,> sqr = delegate(int item) | |||
{ | { | ||
return item*item; | return item*item; | ||
Line 288: | Line 300: | ||
=== C === | === 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. [http://jens.mooseyard.com/2008/08/blocksclosures-for-c/ Blocks for C],[http://arstechnica.com/apple/reviews/2009/08/mac-os-x-10-6.ars/10 Closures in Mac OS 10.6] | 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. [http://jens.mooseyard.com/2008/08/blocksclosures-for-c/ Blocks for C<sup>9</sup>],[http://arstechnica.com/apple/reviews/2009/08/mac-os-x-10-6.ars/10 Closures in Mac OS 10.6<sup>10</sup>] | ||
Here is an example. | Here is an example. | ||
<pre> | <pre> | ||
Line 298: | Line 310: | ||
=== Perl === | === 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.[http://www.perl.com/pub/2002/05/29/closure.html Perl Documentation] | 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.[http://www.perl.com/pub/2002/05/29/closure.html Perl Documentation<sup>11</sup>] | ||
Taking our squaring example, we can write it in perl as | Taking our squaring example, we can write it in perl as | ||
<pre> | <pre> | ||
Line 315: | Line 327: | ||
Closures in Python are implemented using Lambda or Nested functions. | Closures in Python are implemented using Lambda or Nested functions. | ||
==== Lambda ==== | ==== Python 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. | Lambda in Python [http://ivan.truemesh.com/archives/000392.html Lambdas in Python<sup>12</sup>] 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 | Carrying on with our previous examples, we can write | ||
<pre> | <pre> | ||
Line 326: | Line 338: | ||
==== Nested Functions ==== | ==== Nested Functions ==== | ||
Another way to write closures in Python is to use nested functions, meaning writing functions inside functions. | Another way to write closures in Python is to use nested functions [http://ynniv.com/blog/2007/08/closures-in-python.html Closures in Python<sup>13</sup>], meaning writing functions inside functions. | ||
Our squaring example can be written in this scheme as | Our squaring example can be written in this scheme as | ||
<pre> | <pre> | ||
Line 350: | Line 362: | ||
! scope="col" | JavaScript | ! scope="col" | JavaScript | ||
! scope="col" | C++ | ! scope="col" | C++ | ||
! scope="col" | C# | |||
! scope="col" | C | |||
! scope="col" | Perl | |||
! scope="col" | Python | |||
|- | |- | ||
! scope="row" | Construct | ! scope="row" | Construct | ||
| [[#Blocks|Blocks]],[[#Procs|Procs]],[[#Lambda|Lambda]],[[#Method|Method]] || [[#Java|Anonymous Inner Classes]] || [[#JavaScript|Nested Functions]] || [[#Overloading ()|Overloading()]],[[#Lambda Expressions|Lambda Expressions]] | | [[#Blocks|Blocks]],[[#Procs|Procs]],[[#Lambda|Lambda]],[[#Method|Method]] || [[#Java|Anonymous Inner Classes]] || [[#JavaScript|Nested Functions]] || [[#Overloading ()|Overloading()]],[[#Lambda Expressions|Lambda Expressions]] || [[#C#|Delegates]] | ||
|| [[#C|Blocks]] || [[#Perl|References to Functions]] ||[[#Python Lambda|Lambda]],[[#Nested Functions|Nested Functions]] | |||
|- | |- | ||
! scope="row" | Example | ! scope="row" | Example | ||
| <pre>do |n| ... end</pre> | |<pre>do |n| ... end</pre> | ||
<pre>square = Proc.new do |n|... | |||
array_1.iterate!(square)</pre> | array_1.iterate!(square)</pre> | ||
<pre>c = lambda{|a,b| puts a +b}</pre> | |||
<pre>array.iterate!(method(:square))</pre> | |||
||<pre> new | ||<pre> new Adapterclass({function()})</pre>||<pre>function outerf{ cube_inner(s) | ||
{.... return inners}return cube_inner}</pre> || | {.... return inners}return cube_inner}</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> | |||
||<pre>func<int> sqr = delegate(int item)</pre> | |||
||<pre>square = ^ int (int a) | |||
{ return a * a; };</pre> | |||
||<pre> return sub { my $sub_arg = shift;..</pre> | |||
||<pre>return lambda i:i*i, int</pre> | |||
<pre>def power(integer): | |||
def calulate(input): | |||
nonlocal integer | |||
input = input**integer | |||
return input | |||
return calculate | |||
</pre> | |||
|- | |- | ||
! scope="row" | Comment | ! scope="row" | Comment | ||
| Most Versatile of all closure providing languages || Java closures are | | Most Versatile of all closure providing languages || Java closures are verbose || failure to declare a variable as var creates an accidental closure in JavaScript || Most closure features are provided in party specific compilers, such as VC++ || Improved function Pointer || Highly vendor specific, currently in MAC OS || A function returns and inner function pointer which completes closure || The return of a lambda can only be a single expression, all variables inside the closure are read only | ||
|} | |} | ||
== References == | |||
1 [http://en.wikipedia.org/wiki/Closure_%28computer_science%29 Closures:Wikipedia] | |||
2 [http://gafter.blogspot.com/2007/01/definition-of-closures.html Gafters Blog: A definition for closures] | |||
3 [http://linuxgazette.net/112/ramankutty.html Closures Definition, Linuxgazette] | |||
4 [http://www.artima.com/intv/closures2.html Blocks and Closures in Ruby] | |||
5 [http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-and-methods/ Closure by Method in Ruby] | |||
6 [http://www.experts-exchange.com/Programming/Languages/Java/A_2690-Closures-in-Java-7-does-a-new-era-start-for-the-language.html Closures in Java 7] | |||
7 [http://jessecravens.com/04092008/understanding-javascript-closures Understanding Closures in Javascript] | |||
8 [http://msdn.microsoft.com/en-us/library/dd293608%28VS.100%29.aspx Lambda Expressions in VC++] | |||
9 [http://jens.mooseyard.com/2008/08/blocksclosures-for-c/ Blocks for C] | |||
10[http://arstechnica.com/apple/reviews/2009/08/mac-os-x-10-6.ars/10 Closures in Mac OS 10.6] | |||
11[http://www.perl.com/pub/2002/05/29/closure.html Perl Documentation] | |||
12[http://ivan.truemesh.com/archives/000392.html Lambdas in Python] | |||
13[http://ynniv.com/blog/2007/08/closures-in-python.html Closures in Python] |
Latest revision as of 00:52, 18 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:Wikipedia1
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 closures2 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.
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 Definition3
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
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:Wikipedia1
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 Ruby4
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 four different ways of creating closures. They are blocks , procs ,lambdas and methods. 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:
class Array def traverse! self.each_with_index do |z, i| self[i] = yield(z) end end end odd_val = [11, 9, 7, 5] odd_val.traverse! do |z| z - 1 end puts odd_val # => [10,8,6,4]
It is apparent from the code that the block interacts with the array elements and decrements each element by 1. It is important to note that the block is automatically converted to proc object and there is no explicit call to it. The way to use it is using ‘yield’ keyword. Hence, blocks are not reusable i.e it the same block cannot be called for a different array. 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 traverse!(obj) self.each_with_index do |z, i| self[i] = obj.call(z) end end end Procsarray = [2,4,5,6] Procsarray2 = [6,5,4,3] decrement = Proc.new do |z| z - 1 end Procsarray.traverse!(decrement) Procsarray2.traverse!(decrement) puts Procsarray.inspect puts Procsarray2.inspect output: [1, 3, 4, 5] [5, 4, 3, 2]
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
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 third statement 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 Method5 Following the previous example used for procs , the only modification in the code is the way ‘square’ function is applied to the array.
def decrement(z) z - 1 end array = [3,4,5,6] array.traverse!(method(:decrement))
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 76. 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 Javascript7 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[5] ; for(var i = 0;i< 5;i++){ Buttons[i].onclick = function () {alert(“Button” + i);}; }}
In here, 5 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 ‘4’.
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<5;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++8 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 C9,Closures in Mac OS 10.610 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 Documentation11 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.
Python Lambda
Lambda in Python Lambdas in Python12 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 Closures in Python13, 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++ | C# | C | Perl | Python | |
---|---|---|---|---|---|---|---|---|
Construct | Blocks,Procs,Lambda,Method | Anonymous Inner Classes | Nested Functions | Overloading(),Lambda Expressions | Delegates | Blocks | References to Functions | Lambda,Nested Functions |
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 Adapterclass({function()}) |
function outerf{ cube_inner(s) {.... return inners}return cube_inner} |
public:bool operator()(int a) {... for_each(v.begin(), v.end(), [&evenCount] (int n).. |
func<int> sqr = delegate(int item) |
square = ^ int (int a) { return a * a; }; |
return sub { my $sub_arg = shift;.. |
return lambda i:i*i, int def power(integer): def calulate(input): nonlocal integer input = input**integer return input return calculate |
Comment | Most Versatile of all closure providing languages | Java closures are verbose | failure to declare a variable as var creates an accidental closure in JavaScript | Most closure features are provided in party specific compilers, such as VC++ | Improved function Pointer | Highly vendor specific, currently in MAC OS | A function returns and inner function pointer which completes closure | The return of a lambda can only be a single expression, all variables inside the closure are read only |
References
2 Gafters Blog: A definition for closures
3 Closures Definition, Linuxgazette