CSC/ECE 517 Fall 2010/ch1 1b gb

From Expertiza_Wiki
Revision as of 02:23, 8 September 2010 by Han (talk | contribs)
Jump to navigation Jump to search

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.increment! do |n|
    n+1
    end
    puts  Set.increment    
    # => [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

puts array.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.


Closures in Languages Other than Ruby

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, SuqaringFunctor 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(), [&evenCount] (int n) 
{
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

}

References

Closures at a Glance
Ruby C++ C#
Construct 1 2 3
Example 2 4 6
Comment 3 6 9