CSC/ECE 517 Fall 2010/ch1 1b YL: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(160 intermediate revisions by 3 users not shown)
Line 1: Line 1:
= Closures in Ruby vs. closures in other languages =
= Closures in Ruby vs. closures in other languages =
[http://en.wikipedia.org/wiki/Closure_(computer_science) Closure] is the important feature of [http://en.wikipedia.org/wiki/Functional_programming functional programming]. [http://en.wikipedia.org/wiki/Ruby_(programming_language) Ruby] is a very well known functional programming language. Other non functional programming languages like [http://en.wikipedia.org/wiki/Java_(programming_language) Java], [http://en.wikipedia.org/wiki/C%2B%2B C++] also support closure like features to some extent. But there are some differences when closures in Ruby and closures in other languages are taken into consideration.
__TOC__


== Closures ==
== Closures ==
A [http://en.wikipedia.org/wiki/Closure_%28computer_science%29 closure] can be defined as


Before discussing semantic and implementation differences of closure implementation in different languages, closures should be discussed first.
<Blockquote>The programming language function which can be passed around like any other object and still remembers the original context where that function is declared first.</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]</Blockquote>
Such a function is said to be "closed over" its free variables. In this definition first-class function is the function which is treated as first-class objects. Specifically, this means that the language supports constructing new functions during the execution of a program, storing them in data structures, passing them as arguments to other functions, and returning them as the values of other functions. [http://en.wikipedia.org/wiki/First-class_function]


So closure can be explained as nothing but the behavior or in programming language function which can be passed around like any other argument and still remembering the original context where these functions are declared first. This way it breaks out of the standard function concept where the variables inside functions can be referenced within the scope of the function. However, in closures these variables can be referred out of the scope of the local functions. This ability of accessing original context makes closure different from normal objects.
Closure is also called [http://en.wikipedia.org/wiki/First-class_function first-class function]. First-class function is the function which is treated as first-class object which can be passed as an argument. Specifically, this means that the language supports constructing new functions during the execution of a program, storing them in data structures, passing them as arguments to other functions, and returning them as the values of other functions.<sup>[http://www.skorks.com/2010/05/closures-a-simple-explanation-using-ruby/]</sup>


Closure concept can be illustrated with the example in JavaScript.
This way, in closures, variables can be referred out of the scope of the local functions. This ability of accessing original context makes closure different from normal objects.


    <source lang="javascript">
Closure concept can be illustrated with an example in JavaScript.
    // Return a list of all employees with at least 'threshold' salary.
    function highlyPaidEmployees(threshold)
    {
        return empList.filter( function (emp) { return emp.salary >= threshold; } );
    }
    </source>


<source lang="javascript">
// Return a list of all employees with at least 'threshold' salary.
function highlyPaidEmployees(threshold)
{
    return empList.filter( function (emp) { return emp.salary >= threshold; } );
}


In above javascript function <code>highlyPaidEmployees</code>, another anonymous function is defined. This function is passed to the <code>Array.filter</code> method with free variable threshold. This free variable is assigned the value that is passed during the function call of highlyPaidEmployees. Thus the anonymous function defined inside is called repeatedly by filter method with free variable threshold having assigned the value passed to the highlyPaidEmployees.  This follows both the properties defined in the closure definition. One is that the function is passed as an argument and function is able to access free variable out of its context.
In above javascript function <code>highlyPaidEmployees</code>, another anonymous function is defined. This function is passed to the <code>Array.filter</code> method with free variable threshold. This free variable is assigned the value that is passed during the function call of <code>highlyPaidEmployees</code>. Thus the anonymous function defined inside is called repeatedly by filter method with free variable threshold having assigned the value passed to the <code>highlyPaidEmployees</code>.  This follows both the properties defined in the closure definition i.e. function being passed as an argument and function being able to access free variable out of its context.


Closure is supported by many languages. Ruby is famous for extensive use of closure. In next few sections comparison of closure implementation is different languages is done.
Closures are supported by many languages, but most famously used in Ruby. The next sections will compare the implementations of closures in different languages.


== Basis of differences in implementations of closure ==
== Basis of differences in implementations of closure ==


Even though many languages support closure concept there are significant differences in closure implementation in different languages. Some languages support closure concepts partially. Considering all these following are the point on the basis of which closures in different languages differ.
Even though many languages support closure concept, there are significant differences in closure implementation in different languages. Some languages support closure concept partially. Closure implementation in different languages differ with respect to following aspects:


* First-class function - Whether language supports passing function as an argument
* First-class function - Whether the language supports passing function as an argument


* Out of context reference - Whether language supports refering variable out of scope of its context
* Out of context reference - Whether the language supports referring variable out of scope of its context


* Copy of variable or reference to a variable location - If language supports Out of context reference of variable then how is it implemented. Whether variable value is copied or same copy of variable is referred.
* [http://en.wikipedia.org/wiki/Currying Function currying] - It is the technique by which function with multiple arguments can be called as a function with chain of functions, each with single argument. Some languages support this  and some do not.


* Function currying - It is the technique by which function with multiple arguments can be called as a function with chain of functions each with single argument. [http://en.wikipedia.org/wiki/Function_currying Function Currying] Some languages support it and some not.
* Control structure using closure - Whether the language supports closure for control structure or not.


* Control structure using closure - Whether language supports closure for control structure or not.
In the next sections, the concept of closures in Ruby, Lisp, ML, C, C++ and Java is explained.
 
* less lines of code - If language supports control structure using closure then it reduces lines of code considerably.


== Closures in Ruby ==
== Closures in Ruby ==


In Ruby closures can be implemented using Blocks, Proc objects and lambda expressions.  
In [http://en.wikipedia.org/wiki/Ruby_(programming_language) Ruby], closures can be implemented using Blocks, Proc objects and lambda expressions.  


=== Blocks ===
=== Blocks ===


Blocks are like closures, because they can refer to variables from their defining context. Within the body of the invoked method, the code block may be called using the yield keyword. Following example explains the concept of blocks in Ruby.
Blocks are like closures, because they can refer to variables from their defining context. Within the body of the invoked method, the code block may be called using the yield keyword. Following example explains the concept of blocks in Ruby.<sup>[http://innig.net/software/ruby/closures-in-ruby.rb]</sup>


    def thrice
def thrice
      yield
    yield
      yield
    yield
      yield
    yield
    end
end
    x = 5
x = 5
    puts "value of x before: #{x}"
puts "value of x before: #{x}"   # value of x before: 5
    thrice { x += 1 }
thrice { x += 1 }
    puts "value of x after: #{x}"
puts "value of x after: #{x}"   # value of x after: 8


In above example x is incremented every time yield is called. Every yield call calls block {x += 1} and it remembers value of x between calls. Even though x is not defined in thrice method, block accesses x from the location where this block was defined. Thus A block remembers the context in which it was defined, and it uses that context whenever it is called.
In the above example, <code>thrice</code> is called. There are three <code>yield</code> statements in <code>thrice</code> method. Each time yield is executed in <code>thrice</code>, it calls block <code>{ x += 1}</code> and increments x by 1. Every <code>yield</code> call remembers value of <code>x</code> during different calls. Even though <code>x</code> is not defined in <code>thrice</code> method, block accesses <code>x</code> from the location where this block is defined. Thus a block remembers the context in which it is defined, and it uses that context whenever it is called.


=== Proc ===
=== Proc ===


But if we want to use same code block multiple times then concept of block is not helpful. As it requires passing this block of code everytime. Instead we can use Proc which is same as procedure in other languages.
If we want to use same code block multiple times then concept of block is not helpful, as it requires passing this block of code everytime. Instead we can use Proc which is same as procedure in other languages.<sup>[http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/]</sup>
 


    class Array
class Array
        def iterate!(code)
    def iterate!(code)
            self.each_with_index do |n, i|
        self.each_with_index do |n, i|
            self[i] = code.call(n)
        self[i] = code.call(n)
            end
         end
         end
     end
     end
    array_1 = [1, 2, 3, 4]
end
    square = Proc.new do |n|
array_1 = [1, 2, 3, 4]
        n ** 2
square = Proc.new do |n|
    end
    n ** 2
    array_1.iterate!(square)
end
    puts array_1.inspect
array_1.iterate!(square)
puts array_1.inspect   # [1, 4, 9, 16]


In above example square Proc is created and passed to the iterate method which iterates over each element of array to square it. Thus code.call inside iterate method executes square Proc for each array element.
In the above example, <code>square</code> Proc is created. As the name suggests, <code>square</code> proc gives square of the passed argument. This <code>square</code> proc object is passed to the <code>iterate!</code> method which iterates over each element of array to square it. To iterate over an array it uses <code>each_with_index</code> method. The statement <code>code.call</code> inside <code>iterate!</code> method executes <code>square</code> Proc for each array element and hence we see all the elements of an array <code>array_1</code> squared in the final output.


=== Lambda ===
=== Lambda ===
Line 84: Line 86:
Some languages support anonymous function or lambda. Proc in Ruby acts similar to lambda or anonymous function. Lambdas are also available in Ruby.
Some languages support anonymous function or lambda. Proc in Ruby acts similar to lambda or anonymous function. Lambdas are also available in Ruby.


    class Array
class Array
        def iterate!(code)
    def iterate!(code)
            self.each_with_index do |n, i|
        self.each_with_index do |n, i|
            self[i] = code.call(n)
        self[i] = code.call(n)
            end
        end
        end
     end
     end
    array = [1, 2, 3, 4]
end
    array.iterate!(lambda { |n| n ** 2 })
array = [1, 2, 3, 4]
    puts array.inspect
array.iterate!(lambda { |n| n ** 2 })
puts array.inspect   # [1, 4, 9, 16]


In above example instead of creating square Proc lambda expression for the same is created and passed around. Lambdas seem to be exactly the same as Procs. However, there are two differences. Differences are provided at [http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ Ruby blocks procs and lambdas]
The above example is almost similar to the Proc example. The only difference is, instead of creating <code>square</code> Proc, lambda expression for the same is created. Here <code>lambda { |n| n ** 2 }</code> is passed as Proc to <code>iterate!</code> method. And thus <code>code.call</code> calls this lambda expression. Lambdas seem to be exactly the same as Procs. However, there are differences. These differences are provided at [http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ Ruby blocks, procs and lambdas].


=== Control Structures Using Closure ===
=== Control Structures Using Closure ===


In Ruby, control structures can be implemented using closure. In languages like C or C++ loops provide all the details like iterator, boundary values of iterator etc. Instead these things are abstracted in Ruby using closure.  
In Ruby, control structures can be implemented using closure. In languages like C or C++, loops provide all the details like iterator, boundary values of iterator etc. Instead, these things are abstracted in Ruby using closure.  


      3.times {puts "Hello"}
3.times {puts "Ruby"}
# prints:  Ruby
#          Ruby
#          Ruby


In above example Hello is printed three times and this is achieved using Blocks in Ruby. Implementing control structure using closure also reduces lines of code.
In the above example, Ruby is printed three times and this is achieved using Blocks in Ruby. Implementing control structure using closure also reduces lines of code.


=== Currying in Ruby Using Closure ===
=== Currying in Ruby Using Closure ===


Ruby supports function currying. Currying means creating a new function out of an existing function by fixing the value of some of its input parameters.
Ruby supports function currying. Currying means creating a new function out of an existing function by fixing the value of some of its input parameters.
A simple example illustrates the concept. Consider a function which raises
A simple example illustrates this concept. Consider a function which raises
its first parameter to the power specified by the second parameter.
its first parameter to the power specified by the second parameter.<sup>[http://pragprog.com/titles/ruby3/programming-ruby-1-9]</sup>
      def power(x,y)
def power(x,y)
          val = 1
    val = 1
          1.upto(y) {|a| val = val * x}
    1.upto(y) {|a| val = val * x}
          val
    val
      end
end
      square = lambda {|x| power(x,2)}
square = lambda {|x| power(x,2)}
      cube = lambda {|x| power(x,3)}
cube = lambda {|x| power(x,3)}
      puts square.call(4)
puts square.call(4)   # prints 16
      puts cube.call(3)
puts cube.call(3)     # prints 27
Thus in above example square and cube functions are created by fixing power parameter to 2 and 3.
 
Thus in the above example, <code>square</code> and <code>cube</code> functions are created by fixing power parameter to 2 and 3.
Instead of defining a new method, the existing one is curried. In Ruby, we can curry a method using lambda.
Instead of defining a new method, the existing one is curried. In Ruby, we can curry a method using lambda.


Line 126: Line 132:
=== Closures in Lisp ===
=== Closures in Lisp ===


Lisp is famous for its usage of Closure.  
[http://en.wikipedia.org/wiki/Lisp Lisp] is famous for its usage of Closure. Following is the example to demonstrate closure like functionality in Lisp.


    (let ((counter 0))
(let ((counter 0))
        (defun new-id () (incf counter))
    (defun new-id () (incf counter))
          (defun reset-id () (setq counter 0)))
        (defun reset-id () (setq counter 0)))
      --> RESET-ID
--> RESET-ID
      (new-id)
(new-id)
      --> 1
--> 1
      (new-id)
(new-id)
      --> 2
--> 2
      (reset-id)
(reset-id)
      --> 0
--> 0


Closures can be retrurned from functions and then
In the above example, both functions <code>new-id()</code> and <code>reset-id()</code> work on the same copy of counter. Even though counter is defined in one context, it is referred out of its scope, which is one of the properties of the closure.
call them with FUNCALL:


    (defun make-adder (n)
Closures can be returned from functions and then called with <code>FUNCALL</code>:
    #'(lambda (x) (+ x n)))
    --> MAKE-ADDER
    (funcall (make-adder 2) 5)
    --> 7
    (funcall (make-adder 12) 500)
    --> 512


Thus Lisp allows referencing variables out of context. Also in above example make-adder method returns anonymous function which can be used to pass as an argument. Thus closures in Lisp satisfies the properties of closures.
(defun make-adder (n)
#'(lambda (x) (+ x n)))
--> MAKE-ADDER
(funcall (make-adder 2) 5)
--> 7
(funcall (make-adder 12) 500)
--> 512
 
In the above example, <code>make-adder</code> method returns anonymous function which can be used to pass as an argument.
 
Thus, Lisp allows referencing variables out of context. Also it allows to treat function as first-class function. Thus closures in Lisp satisfiy the properties of closures.


=== Closures in ML ===
=== Closures in ML ===
[http://en.wikipedia.org/wiki/ML_(programming_language) ML] is a functional language which supports closures and function currying.
Consider the following closure example.<sup>[http://www.cs.cmu.edu/~rwh/smlbook/offline.pdf]</sup>
val x = 5
fun f y = x * y
val x = 8
val z = f 10    # z becomes 50
Here the value of <code>z</code> becomes 50 and not 80. This is because of lexical scoping. When a function expression is evaluated, a copy of the environment is attached to the function. Subsequently, all free variables of the function (i.e., those not occurring as parameters) are resolved with respect to the environment attached to the function; the function is therefore said to be “closed” with respect to the attached environment. While applying the function, the active environment is replaced by function's attached environment and it is restored after the completion of function call.
In the above example, environment associated with the function contains the declaration <code>val x = 5</code> to record the fact that at the time the function was evaluated, the variable <code>x</code> was bound to the value 5. The variable <code>x</code> is subsequently re-bound to 8, but when <code>f</code> is applied, the binding of <code>x</code> is temporarily reinstated to 5.
To understand the concept of function currying in ML, consider the following simple example of map:
fun map' (f, nil) = nil
  | map' (f, h::t) = (f h) :: map' (f, t)
When a function is passed to <code>map'</code> function, it is applied to every element of the list.
e.g. map' (fn x => x+1, [1,2,3]) evaluates to the list [2,3,4]
Now consider a <code>map</code> function that is specialized to the given function <code>f</code> that can be applied to different lists.
fun map f nil = nil
  | map f (h::t) = (f h) :: (map f t)
The function <code>map</code> takes a function of type <code>('a->'b)</code> as an argument and yields another function of type <code>'a list -> 'b list</code> as a result. Thus, a two-argument function (more properly, a function taking a pair as an argument) is changed to a function that takes two arguments in succession, yielding the first function that takes the second as its sole argument. This is function currying.


=== Closures in C ===
=== Closures in C ===


The C language does not support closures directly, but it has some extensions which add closures like functionality. Nested functions are similar to closures.
The [http://en.wikipedia.org/wiki/C_language C] language does not support closure directly, but it has some extensions which add closure like functionality. Nested functions satisfy some properties of closure.


A nested function is a function defined inside another function. It's scope is limited to the enclosing function. The nested function can access all the variables of the containing function that are visible at the point of its definition. This is called lexical scoping.
A nested function is a function defined inside another function. It's scope is limited to the enclosing function. The nested function can access all the variables of the containing function that are visible at the point of its definition. <sup>[http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html#Nested-Functions]</sup> This is called lexical scoping.


    int arrayProcess (int *array, int offset, int size)
int arrayProcess (int *array, int offset, int size)
    {
{
      int arrayAccess (int *array, int index)
    int arrayAccess (int *array, int index)
        { return array[index + offset]; }
      { return array[index + offset]; }     // arrayAccess can access outer function's(arrayProcess) 'offset' variable
      int i;
    int i;
      /* ... */
    /* ... */
      for (i = 0; i < size; i++)
    for (i = 0; i < size; i++)
         /* ... */ access (array, i) /* ... */
         /* ... */ access (array, i) /* ... */
    }
}
Here the inner function arrayAccess can refer to outer function's variable 'offset'.
 
Here, the inner function <code>arrayAccess</code> can refer to outer function's variable <code>offset</code>.


The nested function can be called from outside the enclosing function by passing its address to another function:
The nested function can be called from outside the enclosing function by passing its address to another function:


It is possible to call the nested function from outside the scope of its name by storing its address or passing the address to another function:
int arrayProcess (int *array, int size)
{
    void store (int index, int value)
      { array[index] = value; }
   
    intermediate (store, size);    // function store passed as an arguemnt
}


    int arrayProcess (int *array, int size)
Here, the address of the function <code>store</code> is passed to the function <code>intermediate</code> as an argument. So, <code>intermediate</code> can call <code>store</code> with <code>index</code> and <code>value</code> arguments. But, <code>intermediate</code> can call <code>store</code> as long as the enclosing function <code>arrayProcess</code> does not exit.
     {
 
      void store (int index, int value)
It is not safe to call the nested function through its address after its enclosing function is exited. But, if the nested function does not refer to anything that has gone out of scope then it will work.
        { array[index] = value; }
 
      
 
      intermediate (store, size);
Another closure like feature C language provides is function pointers.<sup>[http://www.newty.de/fpt/fpt.html]</sup>
     }
 
int addition(int a, int b)
{
     return a + b;
}
// <ptr2Func> is a pointer to a function which takes two int values and returns an int
void getPoniter(int (*ptr2Func)(int, int))
{
    int result = (*ptr2Func)(10,20);        // call using function pointer
    printf("Result = " + result);           // Result = 30
}
void passPoniter()
{
     int (*ptr2Function)(int, int) = NULL;
     ptr2Function = &addition;              //& is optional here but prefered
    getPoniter(ptr2Function);
}


Here, the address of the function store is passed to the function intermediate as an argument. So, intermediate can call store with index and value arguments. But, intermediate can call store so long as the enclosing function arrayProcess does not exit.
Function pointers are nothing else but variables. In the above example, <code>ptr2Function</code> is a pointer to the function <code>addition</code> which takes two integers and returns an integer. It is then passed to another function <code>getPointer()</code>, which can then call the function <code>addition</code> using that pointer.
Function pointer can be passed as an argument which is one of the desired properties of the closures.


It is not safe to call the nested function through its address after its enclosing function is exited. But, if the nested function does not refer to anything that has gone out of scope, then it will work.
=== Closures in C++ ===


[http://en.wikipedia.org/wiki/C%2B%2B C++] does not support nested function like C does. But, it supports function pointers similar to C.
Also, C++ has Boost library which provides lambda expressions.


Another closure like feature C language provides is function pointers.  
Here is a simple example of Boost lambda expressions in Standard Template Library(STL).


    int addition(int a, int b)
list<int> v(10);
    {
for_each(v.begin(), v.end(), _1 = 1);   // initializes to v[0]=1, v[1]=1,.., v[9]=1
        return a + b;
    }


    // <ptr2Func> is a pointer to a function which takes two int values and returns an int
In the C++ version of lambda expressions, formal parameters have predefined names. In the current version of the library, there are three such predefined formal parameters, called placeholders: <code>_1</code>, <code>_2</code> and <code>_3</code>. They refer to the first, second and third argument of the function defined by the lambda expression.
    void getPoniter(int (*ptr2Func)(int, int))
The expression <code>_1 = 1</code> creates a lambda functor which assigns the value 1 to every element in <code>v</code>.
    {
        int result = (*ptr2Func)(10,20);        // call using function pointer
        printf("Result = " + result);
    }


    void passPoniter()
More on Boost libraries can be found at Boost library website [http://www.boost.org/]
    {
        int (*ptr2Function)(int, int) = NULL;
        ptr2Function = &addition;              //& is optional here but prefered
        getPoniter(ptr2Function);
    }


Function pointers are nothing else than variables. In the code above, ptr2Function is pointer to function addition which takes two integers and returns one integer. It is then passed to another function getPointer(), which can then call the function addition using that pointer.
Thus, C++ supports first-class functions as it has function pointers and they can be passed as arguments. It also supports control structures using closure in terms of Boost library lambda expressions.
Function pointer can be passed as an argument which is one of the desired property of the closures.


=== Closures in C++ ===
=== Closures in Java ===


C++ does not support nested function as C. But, it supports function pointers like C.
A closure in [http://en.wikipedia.org/wiki/Java_(programming_language) Java] is implemented using anonymous function. It is declared using the syntax
C++ has some libraries like Boost libraries which provide lambda expressions.
{ formal parameters => statements expression }. For example, <code>{ int i => i + 1 }</code> is a function that takes a single int argument and returns its value incremented by 1. A closure can be invoked by the <code>invoke</code> method. For example, <code>{ int i => i + 1 }.invoke(1)</code> will call the closure with argument 1. Below is the Java class implementing closure.<sup>[http://tronicek.blogspot.com/2007/12/closures-closure-is-form-of-anonymous_28.html]</sup>


Here is a simple examples of Boost lambda expressions in Standard Template Library(STL).
public class SimpleClosure {
    public static void main(String[] args) {
        // function with one argument; return value is the passed value incremented by 1
        int answer = {int x => x+1 }.invoke(10);
        System.out.println(answer);    // answer = 11
    }
}


    list<int> v(10);
In the above <code>main</code> function, the anonymous function accepts an argument, increments passed value by 1 and returns it. In the above example answer will be 11.
    for_each(v.begin(), v.end(), _1 = 1);


In the C++ version of lambda expressions, formal parameters have predefined names. In the current version of the library, there are three such predefined formal parameters, called placeholders: _1, _2 and _3. They refer to the first, second and third argument of the function defined by the lambda expression.
Each function that takes multiple arguments can be transformed into a function that takes a single argument. For example, function <code>plus</code> can be transformed into <code>anotherPlus</code>:<sup>[http://tronicek.blogspot.com/2007/12/advanced-features.html]</sup>
The expression _1 = 1 creates a lambda functor which assigns the value 1 to every element in v.


More on Boost libraries can be found at [http://www.boost.org/ Boost libraries]
{ int, int => int } plus = { int x, int y => x + y };
{ int => { int => int } } anotherPlus = { int x => { int y => x + y } };
int threePlusFour = anotherPlus.invoke(3).invoke(4);    // threePlusFour = 7


=== Closures in Java ===
Thus Java implements function currying using anonymous functions.


== Comparison ==
== Comparison ==
Comparison of closures in different languages can be done on the basis of the factors defined in section 2. Below is the tabular comparison.
{| class="wikitable" | border="1"
|+ Comparison of closures in Ruby with closures in different languages
|-
! Factor
! align="center" | Closures in Ruby
! align="center" | Closures in Lisp
! align="center" | Closures in ML
! align="center" | Closures in C
! align="center" | Closures in C++
! align="center" | Closures in Java
|-
| align="center" | First-class function
| align="center" | Yes
| align="center" | Yes
| align="center" | Yes
| align="center" | Yes
| align="center" | Yes
| align="center" | Yes
|-
| align="center" | Out of context variable reference
| align="center" | Yes
| align="center" | Yes
| align="center" | Yes
| align="center" | No
| align="center" | Yes
| align="center" | Yes
|-
| align="center" | Function currying
| align="center" | Yes
| align="center" | Yes
| align="center" | Yes
| align="center" | No
| align="center" | Yes
| align="center" | No
|-
| align="center" | Control structure using closures
| align="center" | Yes
| align="center" | No
| align="center" | No
| align="center" | No
| align="center" | Yes
| align="center" | No
|}


== Conclusion ==
== Conclusion ==
Closures are extensively used in Ruby. Not only advanced features but very simple language features like control structures are implemented using closure. As a result Ruby has always less lines of code compared to other languages.
Closure is becoming popular day by day and hence it is being introduced and used in non-functional languages also.


== References ==
== References ==


1) [http://innig.net/software/ruby/closures-in-ruby.rb Closures in Ruby]
# [http://www.skorks.com/2010/05/closures-a-simple-explanation-using-ruby/ Closures - a simple explanation using ruby]
 
# [http://innig.net/software/ruby/closures-in-ruby.rb Closures in Ruby].
2) [http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ Ruby blocks, procs and lambdas]
# [http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas Ruby blocks, procs and lambdas].
# [http://pragprog.com/titles/ruby3/programming-ruby-1-9 Programming Ruby 1.9: The Pragmatic Programmers' Guide].
# [http://www.cs.cmu.edu/~rwh/smlbook/offline.pdf Programming in Standard ML].
# [http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html#Nested-Functions Nested functions in the C Language].
# [http://www.newty.de/fpt/fpt.html The Function Pointer Tutorials].
# [http://www.boost.org/ Boost C++ Libraries].
# [http://tronicek.blogspot.com/2007/12/closures-closure-is-form-of-anonymous_28.html Java closures].
# [http://tronicek.blogspot.com/2007/12/advanced-features.html Currying in Java].

Latest revision as of 06:10, 26 October 2010

Closures in Ruby vs. closures in other languages

Closure is the important feature of functional programming. Ruby is a very well known functional programming language. Other non functional programming languages like Java, C++ also support closure like features to some extent. But there are some differences when closures in Ruby and closures in other languages are taken into consideration.

Closures

A closure can be defined as

The programming language function which can be passed around like any other object and still remembers the original context where that function is declared first.

Closure is also called first-class function. First-class function is the function which is treated as first-class object which can be passed as an argument. Specifically, this means that the language supports constructing new functions during the execution of a program, storing them in data structures, passing them as arguments to other functions, and returning them as the values of other functions.[1]

This way, in closures, variables can be referred out of the scope of the local functions. This ability of accessing original context makes closure different from normal objects.

Closure concept can be illustrated with an example in JavaScript.

<source lang="javascript">
// Return a list of all employees with at least 'threshold' salary.
function highlyPaidEmployees(threshold) 
{
    return empList.filter( function (emp) { return emp.salary >= threshold; } );
}

In above javascript function highlyPaidEmployees, another anonymous function is defined. This function is passed to the Array.filter method with free variable threshold. This free variable is assigned the value that is passed during the function call of highlyPaidEmployees. Thus the anonymous function defined inside is called repeatedly by filter method with free variable threshold having assigned the value passed to the highlyPaidEmployees. This follows both the properties defined in the closure definition i.e. function being passed as an argument and function being able to access free variable out of its context.

Closures are supported by many languages, but most famously used in Ruby. The next sections will compare the implementations of closures in different languages.

Basis of differences in implementations of closure

Even though many languages support closure concept, there are significant differences in closure implementation in different languages. Some languages support closure concept partially. Closure implementation in different languages differ with respect to following aspects:

  • First-class function - Whether the language supports passing function as an argument
  • Out of context reference - Whether the language supports referring variable out of scope of its context
  • Function currying - It is the technique by which function with multiple arguments can be called as a function with chain of functions, each with single argument. Some languages support this and some do not.
  • Control structure using closure - Whether the language supports closure for control structure or not.

In the next sections, the concept of closures in Ruby, Lisp, ML, C, C++ and Java is explained.

Closures in Ruby

In Ruby, closures can be implemented using Blocks, Proc objects and lambda expressions.

Blocks

Blocks are like closures, because they can refer to variables from their defining context. Within the body of the invoked method, the code block may be called using the yield keyword. Following example explains the concept of blocks in Ruby.[2]

def thrice
    yield
    yield
    yield
end
x = 5
puts "value of x before: #{x}"    # value of x before: 5
thrice { x += 1 }
puts "value of x after: #{x}"    # value of x after: 8

In the above example, thrice is called. There are three yield statements in thrice method. Each time yield is executed in thrice, it calls block { x += 1} and increments x by 1. Every yield call remembers value of x during different calls. Even though x is not defined in thrice method, block accesses x from the location where this block is defined. Thus a block remembers the context in which it is defined, and it uses that context whenever it is called.

Proc

If we want to use same code block multiple times then concept of block is not helpful, as it requires passing this block of code everytime. Instead we can use Proc which is same as procedure in other languages.[3]


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]
square = Proc.new do |n|
    n ** 2
end
array_1.iterate!(square)
puts array_1.inspect    # [1, 4, 9, 16]

In the above example, square Proc is created. As the name suggests, square proc gives square of the passed argument. This square proc object is passed to the iterate! method which iterates over each element of array to square it. To iterate over an array it uses each_with_index method. The statement code.call inside iterate! method executes square Proc for each array element and hence we see all the elements of an array array_1 squared in the final output.

Lambda

Some languages support anonymous function or lambda. Proc in Ruby acts similar to lambda or anonymous function. Lambdas are also available in Ruby.

class Array
    def iterate!(code)
        self.each_with_index do |n, i|
        self[i] = code.call(n)
        end
    end
end
array = [1, 2, 3, 4]
array.iterate!(lambda { |n| n ** 2 })
puts array.inspect    # [1, 4, 9, 16]

The above example is almost similar to the Proc example. The only difference is, instead of creating square Proc, lambda expression for the same is created. Here lambda { |n| n ** 2 } is passed as Proc to iterate! method. And thus code.call calls this lambda expression. Lambdas seem to be exactly the same as Procs. However, there are differences. These differences are provided at Ruby blocks, procs and lambdas.

Control Structures Using Closure

In Ruby, control structures can be implemented using closure. In languages like C or C++, loops provide all the details like iterator, boundary values of iterator etc. Instead, these things are abstracted in Ruby using closure.

3.times {puts "Ruby"}
# prints:  Ruby
#          Ruby
#          Ruby

In the above example, Ruby is printed three times and this is achieved using Blocks in Ruby. Implementing control structure using closure also reduces lines of code.

Currying in Ruby Using Closure

Ruby supports function currying. Currying means creating a new function out of an existing function by fixing the value of some of its input parameters. A simple example illustrates this concept. Consider a function which raises its first parameter to the power specified by the second parameter.[4]

def power(x,y)
    val = 1
    1.upto(y) {|a| val = val * x}
    val
end
square = lambda {|x| power(x,2)}
cube = lambda {|x| power(x,3)}
puts square.call(4)    # prints 16
puts cube.call(3)      # prints 27

Thus in the above example, square and cube functions are created by fixing power parameter to 2 and 3. Instead of defining a new method, the existing one is curried. In Ruby, we can curry a method using lambda.

Closures in other languages

Closures in Lisp

Lisp is famous for its usage of Closure. Following is the example to demonstrate closure like functionality in Lisp.

(let ((counter 0))
    (defun new-id () (incf counter))
        (defun reset-id () (setq counter 0)))
--> RESET-ID
(new-id)
--> 1
(new-id)
--> 2
(reset-id)
--> 0

In the above example, both functions new-id() and reset-id() work on the same copy of counter. Even though counter is defined in one context, it is referred out of its scope, which is one of the properties of the closure.

Closures can be returned from functions and then called with FUNCALL:

(defun make-adder (n)
#'(lambda (x) (+ x n)))
--> MAKE-ADDER
(funcall (make-adder 2) 5)
--> 7
(funcall (make-adder 12) 500)
--> 512

In the above example, make-adder method returns anonymous function which can be used to pass as an argument.

Thus, Lisp allows referencing variables out of context. Also it allows to treat function as first-class function. Thus closures in Lisp satisfiy the properties of closures.

Closures in ML

ML is a functional language which supports closures and function currying. Consider the following closure example.[5]

val x = 5
fun f y = x * y
val x = 8
val z = f 10    # z becomes 50

Here the value of z becomes 50 and not 80. This is because of lexical scoping. When a function expression is evaluated, a copy of the environment is attached to the function. Subsequently, all free variables of the function (i.e., those not occurring as parameters) are resolved with respect to the environment attached to the function; the function is therefore said to be “closed” with respect to the attached environment. While applying the function, the active environment is replaced by function's attached environment and it is restored after the completion of function call.

In the above example, environment associated with the function contains the declaration val x = 5 to record the fact that at the time the function was evaluated, the variable x was bound to the value 5. The variable x is subsequently re-bound to 8, but when f is applied, the binding of x is temporarily reinstated to 5.

To understand the concept of function currying in ML, consider the following simple example of map:

fun map' (f, nil) = nil
  | map' (f, h::t) = (f h) :: map' (f, t)

When a function is passed to map' function, it is applied to every element of the list. e.g. map' (fn x => x+1, [1,2,3]) evaluates to the list [2,3,4] Now consider a map function that is specialized to the given function f that can be applied to different lists.

fun map f nil = nil
  | map f (h::t) = (f h) :: (map f t)

The function map takes a function of type ('a->'b) as an argument and yields another function of type 'a list -> 'b list as a result. Thus, a two-argument function (more properly, a function taking a pair as an argument) is changed to a function that takes two arguments in succession, yielding the first function that takes the second as its sole argument. This is function currying.

Closures in C

The C language does not support closure directly, but it has some extensions which add closure like functionality. Nested functions satisfy some properties of closure.

A nested function is a function defined inside another function. It's scope is limited to the enclosing function. The nested function can access all the variables of the containing function that are visible at the point of its definition. [6] This is called lexical scoping.

int arrayProcess (int *array, int offset, int size)
{
    int arrayAccess (int *array, int index)
     { return array[index + offset]; }      // arrayAccess can access outer function's(arrayProcess) 'offset' variable
    int i;
    /* ... */
    for (i = 0; i < size; i++)
        /* ... */ access (array, i) /* ... */
}

Here, the inner function arrayAccess can refer to outer function's variable offset.

The nested function can be called from outside the enclosing function by passing its address to another function:

int arrayProcess (int *array, int size)
{
    void store (int index, int value)
     { array[index] = value; }
    
    intermediate (store, size);    // function store passed as an arguemnt
}

Here, the address of the function store is passed to the function intermediate as an argument. So, intermediate can call store with index and value arguments. But, intermediate can call store as long as the enclosing function arrayProcess does not exit.

It is not safe to call the nested function through its address after its enclosing function is exited. But, if the nested function does not refer to anything that has gone out of scope then it will work.


Another closure like feature C language provides is function pointers.[7]

int addition(int a, int b)
{
    return a + b;
}
// <ptr2Func> is a pointer to a function which takes two int values and returns an int
void getPoniter(int (*ptr2Func)(int, int))
{
    int result = (*ptr2Func)(10,20);        // call using function pointer
    printf("Result = " + result);           // Result = 30
}
void passPoniter()
{
    int (*ptr2Function)(int, int) = NULL;
    ptr2Function = &addition;               //& is optional here but prefered
    getPoniter(ptr2Function);
}

Function pointers are nothing else but variables. In the above example, ptr2Function is a pointer to the function addition which takes two integers and returns an integer. It is then passed to another function getPointer(), which can then call the function addition using that pointer. Function pointer can be passed as an argument which is one of the desired properties of the closures.

Closures in C++

C++ does not support nested function like C does. But, it supports function pointers similar to C. Also, C++ has Boost library which provides lambda expressions.

Here is a simple example of Boost lambda expressions in Standard Template Library(STL).

list<int> v(10);
for_each(v.begin(), v.end(), _1 = 1);    // initializes to v[0]=1, v[1]=1,.., v[9]=1

In the C++ version of lambda expressions, formal parameters have predefined names. In the current version of the library, there are three such predefined formal parameters, called placeholders: _1, _2 and _3. They refer to the first, second and third argument of the function defined by the lambda expression. The expression _1 = 1 creates a lambda functor which assigns the value 1 to every element in v.

More on Boost libraries can be found at Boost library website [8]

Thus, C++ supports first-class functions as it has function pointers and they can be passed as arguments. It also supports control structures using closure in terms of Boost library lambda expressions.

Closures in Java

A closure in Java is implemented using anonymous function. It is declared using the syntax { formal parameters => statements expression }. For example, { int i => i + 1 } is a function that takes a single int argument and returns its value incremented by 1. A closure can be invoked by the invoke method. For example, { int i => i + 1 }.invoke(1) will call the closure with argument 1. Below is the Java class implementing closure.[9]

public class SimpleClosure {
    public static void main(String[] args) {
        // function with one argument; return value is the passed value incremented by 1
        int answer = {int x => x+1 }.invoke(10);
        System.out.println(answer);    // answer = 11
    }
}

In the above main function, the anonymous function accepts an argument, increments passed value by 1 and returns it. In the above example answer will be 11.

Each function that takes multiple arguments can be transformed into a function that takes a single argument. For example, function plus can be transformed into anotherPlus:[10]

{ int, int => int } plus = { int x, int y => x + y };
{ int => { int => int } } anotherPlus = { int x => { int y => x + y } };
int threePlusFour = anotherPlus.invoke(3).invoke(4);    // threePlusFour = 7

Thus Java implements function currying using anonymous functions.

Comparison

Comparison of closures in different languages can be done on the basis of the factors defined in section 2. Below is the tabular comparison.

Comparison of closures in Ruby with closures in different languages
Factor Closures in Ruby Closures in Lisp Closures in ML Closures in C Closures in C++ Closures in Java
First-class function Yes Yes Yes Yes Yes Yes
Out of context variable reference Yes Yes Yes No Yes Yes
Function currying Yes Yes Yes No Yes No
Control structure using closures Yes No No No Yes No

Conclusion

Closures are extensively used in Ruby. Not only advanced features but very simple language features like control structures are implemented using closure. As a result Ruby has always less lines of code compared to other languages.

Closure is becoming popular day by day and hence it is being introduced and used in non-functional languages also.

References

  1. Closures - a simple explanation using ruby
  2. Closures in Ruby.
  3. Ruby blocks, procs and lambdas.
  4. Programming Ruby 1.9: The Pragmatic Programmers' Guide.
  5. Programming in Standard ML.
  6. Nested functions in the C Language.
  7. The Function Pointer Tutorials.
  8. Boost C++ Libraries.
  9. Java closures.
  10. Currying in Java.