CSC/ECE 517 Fall 2012/ch1 1w4 aj

From Expertiza_Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Closures in Ruby Vs. Closures in other Languages

Introduction

This article aims to explore the closure implementations, primarily in Ruby and also in other dynamic scripting languages like C#, JavaScript, Perl and Python. At the end of this article, we intend to present a comparison in the implementations of closures in all the languages, since each language handles it differently. The comparison is provided only to show how the closures are implemented. The article is not intended to be a reference guide for closures, but more like a quick start guide to understanding closures. References and additional learning resources are provided for the reader to go and explore the world of closures in much more detail

Code Blocks

Before understanding the concept of Closures, let us take a brief introduction on “Code Blocks” in Ruby. A code block is a chunk of code, Ruby statements and expressions written between curly braces { } or between “do…end”. For example:

 {  puts "Hello World!"  }

or

  do
     3.times(puts "Hello")
     object1.call
  end

Generally, as per Ruby standard, braces are used for single-line blocks and do...end for multiline blocks. Also, braces have a higher preference than do/end. A code block may appear only immediately after a method is invoked. If a method has parameters, then the block will look as follows:

 random_method("John") { puts "How you doing? " }

Closures in Ruby

What is a Closure?

Now, a block as shown before can use local variables from the surrounding scope. Such blocks are called Closures. Let us look at a simple example<ref>Thomas,D. , Fowler, C. , Hunt, A. , "Programming Ruby 1.9, The Pragmatic Programmers' Guide", The Pragmatic Programmers,LLC (2009)</ref>:

def closurefunc(inc)
     lambda {|val| val + inc }
  end

  p1 = closurefunc(3)
  p1.call(1)    # => 4
 
  p2 = closurefunc(8)
  p2.call(5)   # => 13

In the above example, the value ‘3’ is assigned to the local variable inc of method closurefunc and value ‘1’ is assigned to inner variable val.

A few definitions of closures are provided below :
"A Closure is a block of executable code that is bunched together with references to the certain variables in scope at the site of its creation, which are retained even when the variables and referenced values go out of scope"

"A closure is a function that captures the bindings of free variables in its lexical context" <ref>Gafter, Neal. "A Definition of Closures" http://gafter.blogspot.com/2007/01/definition-of-closures.html</ref>

To avoid jargon, this is a more pertinent definition of Closures<ref>Cantrell, Paul."Closures in Ruby" http://innig.net/software/ruby/closures-in-ruby</ref> :

"A closure is a block of code which meets three criteria: It can be passed around as a value and executed on demand by anyone who has that value, at which time it can refer to variables from the context in which it was created (i.e. it is closed with respect to variable access, in the mathematical sense of the word "closed")"

How does it work?

Let us look at a similar example, but this time, with strings.

 
def concat(param)
     lambda { |greet| greet + param }
  end

  p1 = concat("John")
  p1.call("Hello")    # => "HelloJohn"
 
  p2 = concat("Jim")
  p2.call("Good morning ")   # => "Good morning Jim"

The method concat returns a Proc object that references the method’s parameter, param. We need to use the call method of the Proc object to execute it. Even though the parameter param is out of scope when the block is called, the parameter is still accessible to the block. This is called a closure; where in the variables in the surrounding scope referenced in a block remain accessible for the life of that block and the life of any Proc object created from that block.


Why are closures needed?

Although Closures are not mandatory requirements for a language, Closures provide an elegant way of binding the environment implicitly. Some of the popular languages like C, C++ and Java don't support Closures. Closures help in writing compact codes by avoiding the use of many arguments, as it closes the local variables in its surrounding.

Other ways to use a closure

Rather than calling the method lambda, following ways can be used to create Proc objects:


(i) Using the ( -> ) syntax
->params { . . . }
Example:
obj = ->(v1,v2) { v1 + v2 }
obj.call(2,3) # => 5

Note: There cannot be any space between > and opening paranthesis.

(ii) By passing a block to the method whose last parameter is prefixed with an ampersand (&). That parameter will receive the block as a Proc object.

def sampmeth(v1, &block)
    puts block.inspect
 end
  sampmeth(1) { "a block" }
  sampmeth(3)

produces:

   #<Proc:0x0b5f5e@/tmp/prog1.rb:4>
  Nil


(iii) By calling Proc.new by associating it with a block

obj = Proc.new { "a block" } 
obj   #=>  #<Proc:0x0a5e5a@/tmp/prog1.rb:1>


Scope of a Closure

Closure remembers the context in which it is defined, and uses that context whenever it is called. The context may include the value of self, constants, local variables, class variables and any defined block.

class ClosureExample
  CONST = 1
  @@class_var = 4

  def return_closure
   local_var = 2
   @instance_var = 3
   lambda { [ CONST, local_var, @instance_var,  @@class_var, yield ] }
  end

  def update_values
    @instance_var += 1
    @@class_var += 1
  end
 end

 ex = ClosureExample.new 
 block = ex.return_closure { "dummy" }
 block.call    # => [ 1, 2, 3, 4, "dummy" ]
 ex.update_values
 block.call    # => [ 1, 2, 4, 5, "dummy" ]

In the above example, the return_closure method returns a lambda that accesses local variable local_var, instance variable instance_var, class variable class_var and constant CONST. Even if the block is not in the scope of the object that contains these values, it is still accessible via the closure. So, when we update these values calling the update_values method, the values accessed via the closure also get updated. Closure is a very handy feature for Ruby developers and is used extensively. The rest of the chapter describes the implementation of Closures in different popular programming languages.

Closures in other languages

A closure or a closure-like implementation is available in most programming languages. Now that we have seen the implementation of closures in Ruby, let us explore the use of closures in other programming languages.

Closures in C#

A closure in C# can be done using Lambda expressions and delegates, where a first-class function[1] references the variables in the surrounding scope. Such a referenced variable is neither a parameter of the function nor a local variable<ref>Hilyard, J. and Teilhet,S., "C# 3.0 Cookbook 3rd edition", O'reilly Pub. (2007)</ref>. For example,

  static void Main(string[] args)
 {
	var obj = ClosureFunc(1);
	Console.Writeline("Output 1= " + obj(2));
	Console.Writeline("Output 2= " + obj(3));
 }
 public static Func<int, int> ClosureFunc(inc)
 {
	Func<int,int> SampleFunc = delegate(int val)
		{
			inc = inc + 1;
			return val + inc;
		};
	return SampleFunc;
 }    

The result obtained is:

Output 1= 4
Output 2= 6

Now, when we call ClosureFunc from Main(),we get a method back that increments a local variable inside the method. inc is a local variable of ClosureFunc() which is accessed inside of the delegate. So, when we call the method twice, the local variable inc gets incremented twice outside of its original scope. What actually happens here is the C# compiler encapsulates the delegate and the associated local variables into a compiler generated class. So, on invoking the delegate, it creates a lambda expression to increment the value of inc and results in calling a method on this class. Another way to write the ClosureFunc is using lambda ( => )

Func<string,string> ClosureFunc = val => val + inc;

Closures in JavaScript

JavaScript is a dynamic and powerful scripting language which allows the use of Closures. An example of a closure in JavaScript is as follows<ref>Bhattacharya, A. , Sunder, K. , "Memory leak patterns in JavaScript", http://www.ibm.com/developerworks/web/library/wa-memleak/index.html</ref>:

  function ClosureFunc(inc)
  { 
        return  SampleFunc (val) {
               return val + inc;
  }
  var obj = ClosureFunc(10);
  obj(5);   // returns 15

Here, when a call is made to the outer function ClosureFunc with a parameter inc, the function returns with a pointer to the inner function SampleFunc, which is assigned to the variable obj.

Closures in Perl

Perl also supports closures extensively. Syntax for implementing closure in Perl<ref> Cozens, S., "Achieving Closure", http://www.perl.com/pub/2002/05/29/closure.html</ref> is similar to that of Ruby, which is as follows:

    sub closurefunc {
	 my $inc = shift;
	my $obj = sub  {
		my $val = shift;
		return $val + $inc;     # uses local variable inc
	};
	return $obj;
   }
   
   my $add3 = closurefunc(3);
   print "5 plus 3 is ":
   print $add3->(5);          #  =>  8

Here, the closurefunc subroutine creates an anonymous function, which uses the local variable inc and returns the object $obj.

Closures in Python

Closures in python<ref>"Python Closures explained", http://www.shutupandship.com/2012/01/python-closures-explained.html</ref> are implemented as function calls. Support for closures has existed in Python since version 2.2, although the syntax of Python closures can actually confuse the user in thinking that the closures are not supported.

Consider following example code for creating an 'closurefunc' function using closures<ref>"Closures in Python : examples implementing Closures in Python", http://ynniv.com/blog/2007/08/closures-in-python.html</ref>:

def closurefunc(x):
 def inc(y):
    # x is "closed" in the definition of inc
    return y + x

return inc

inc5 = closurefunc(5)
inc10 = closurefunc(10)

inc5 (5) # returns 10

As mentioned above, closures in Python are executed as function calls. The call to closurefunc creates a binding for x which is referenced inside the function inc. In technical terms, the function inc is closed over the variable x.

If we go ahead and delete the closurefunc function from the global namespace,

del closurefunc

even then,

>>inc10(5) # returns 15

Why does this happen? Each call to closurefunc creates a new instance, returning an inc function object and assigning it to the inc5 and inc10. Each instance has a link to a different binding of x. Hence, the function inc will have access to x even if the scope where x was defined doesn’t exist anymore.

The above example shows the closure of x being used to eliminate either a global or a constant, depending on the nature of x.

Python also supports the use of closures through the lambda constructs.

The difference between a normal function and a lambda function is shown below


>>> def f (x): return x**2  #normal function definition
... 
>>> print f(8)
64

>>> g = lambda x: x**2      #demo of lambda construct
>>> 
>>> print g(8)
64

As you can see, the lambda function is defined on the fly and always returns an expression. If we write a new closurefunc function using the lambda construct, we will see the following


>>def closurefunc(n): return lambda x: x + n #creation of lambda function	

>>f = closurefunc(2)
>>g = closurefunc(6)
 
>>print f(42), g(42)
>>44, 48
 

The lambda function is created on the fly and returns an expression which is assigned to f and g. The lambda construct works even without assigning the returned expression, as shown next

>>print closurefunc(22)(33)
>>55


Conclusion

In conclusion, a brief introduction to closures and its usage in dynamic scripting languages has been provided above. The code examples illustrate the syntax and semantics supported by these languages. A concise comparison between the implementation in these languages is summarized below. References are provided for the users to enhance their understanding of the subject.

Ruby C# JavaScript Perl Python C / C++ / Java
Support for Closures Yes Yes Yes Yes Yes No
Closure implementation using Proc, block and Lambdas Delegates and First Class functions Unnamed functions Anonymous functions Named function calls, Lambda No
Support for Lambda implementation Yes Yes No No direct support, can be simulated using anonymous functions Yes No


Topical References

<references/>

Further Reading

Wikipedia - Closures : everything there is to know about Closures on one page.

Reg Braithwaite - Closures and Higher-Order Functions : gives Ruby examples of specialized Closures.

Closures in Ruby : gives a detailed explanation of Closures in Ruby.

MSDN Magazine - Functional Programming .NET Development : examples of functional style with Closures in C#.

Eric Kidd - Some useful closures, in Ruby : demonstrates more examples of curried and specialized Closures in Ruby.

Jim Weirich - Top Ten Reasons I Like Ruby - Blocks and Closures : provides several examples of how Closures can be useful in Ruby.

C# in Depth - The Beauty of Closures : demonstrates Closures in C#.

Martin Fowler - Closure : provides a basic definition of Closures and gives a few very basic examples.

Javascript Closures : demonstrates Javascript Closures in callbacks.

Alan Skorkin - Closures - A Simple Explanation : gives a high-level overview of Closures using Ruby examples.

IBM Developerworks - Crossing borders : Closures : gives Ruby examples where Closures are useful.

Sam Danielson - An Introduction to Closures in Ruby : high-level overview of using Closures in Ruby.