CSC/ECE 517 Fall 2011/ch1 1d ss

From Expertiza_Wiki
Jump to navigation Jump to search

Closures in statically typed languages. Most languages that implement closures are dynamically typed. It is a challenge to implement closures in a statically typed language. Explain why, and cover attempts to mix the two. Consider also closures and static scoping, as in Scheme.

Introduction

We start off with a brief difference between statically and dynamically typed languages.We try to explain what a closure is, its advantages, how it can be implemented in various typed languages, why is it easier or difficult in some languages.Finally we conclude with static scoping.

Statically vs Dynamically typed

One simple way to differentiate between the two is:
In statically typed languages,type checking is done at the compile time where as in dynamically typed languages, type checking is done at run-time.

Examples of Statically typed.: C,C++,Java,JADE,Pascal etc<ref> http://en.wikipedia.org/wiki/Type_system#Static_typing Static Typing </ref>
Examples of Dynamically typed : PHP,Prolog,Python,Ruby,Small talk etc.<ref> http://en.wikipedia.org/wiki/Type_system#Static_typing Static Typing </ref>

Closures

In the words of Matsumoto, the creator of Ruby language: A closure object has code to run, the executable, and state around the code, the scope. So you capture the environment, namely the local variables, in the closure. As a result, you can refer to the local variables inside a closure. Even after the function has returned, and its local scope has been destroyed, the local variables remain in existence as part of the closure object. When no one refers to the closure anymore, it's garbage collected, and the local variables go away. <ref>http://www.artima.com/intv/closures2.html Blocks and Closures</ref>

What exactly is Closure

  • A closure is a first-class block of code that has access to the environment in which it was defined.
    • A first class function is one that can be passed around just like any other object.
    • The function can access ‘free variables’, ie, variables that are not an argument to, or a local variable of that function. For example, if we have a function that returns a lambda function:


public Func<int,int> GetFunc()
{
      int y = 4;
      Func<int, int> myfunc = x => { return x+y; };
      return myfunc;
}

y is neither an input parameter nor a local variable declared within myfunc. The free variable is bound in the lexical environment. This means that even when GetFunc goes out of scope, myfunc will still have access to it. <ref>http://www.codethinked.com/c-closures-explained C# Closures</ref>

Advantages of Closures

  • It allows access to contextual information that wouldn’t be available inside a standard method of a class.
  • It can be passed around as an object and retain that context, even if the variables are outside their original scope.
  • There is no need to pass around internal variables for every call.
  • Offers a more concise and clean method of programming operations.

Implementation of Closures

In dynamically typed languages

We give the implementations of Closures in some of the dynamic languages.

Example in Ruby

Ruby implements closures with the support of procs and lambdas.These constructs are similar with subtle differences.Here is an example of closure in Ruby.

class SomeClass
def initialize(value1)
    @value1 = value1
  end

  def value_printer(value2)
    lambda {puts "Value1: #{@value1}, Value2: #{value2}"}
  end
end

def caller(some_closure)
  some_closure.call
end

some_class = SomeClass.new(5)
printer = some_class.value_printer("some value")

caller(printer)

when executed, we get the following ,value1 =5 and value2 = some value
As you can see, the value_printer function creates a closure, using the lambda construct, and then returns it. We then assign our closure to a variable and pass that variable to another function, which then calls our closure. This satisfies the first property of a closure – we can pass it around. Notice also that when we called our closure, we printed out "5" and "some value". Even though both the @value1 and value2 variables were both well and truly out of scope in the rest of the program when we finally called the closure; inside the closure they were still in scope as it retained the state of all the variables that were in scope when it was defined. <ref>http://www.skorks.com/2010/05/closures-a-simple-explanation-using-ruby/ Closures in Ruby</ref>

Example in JS

we can access private members via closures in JS.As private members can only be accessed from inside your function,this comes handy.The same holds true for private methods(or functions,since we are in JavaScript here).This can be easily done with closure.

var namespace = {};
(namespace.someClass = function() {
    var _privateProperty = "some value";
    function _privateMethod() {
        //perform some stuff
    }
    return {
        publicProperty: "some value",
        publicMethod: function publicMethod() {
            //perform some stuff
        }
    }
}()); 

By looking closer at what exactly is happening, you'll notice that namespace.someClass is equal to an auto invoked function that returns an object literal.when executed an object that is assigned to namespace.someClass._privateProperty and _privateMethod() get closured and are now available to someClass,but since their containing function is no longer in scope, they are not available to anyone else. <ref>http://tinyhippos.com/2010/07/05/closure-in-javascript-with-examples/ Closures in JS</ref>

Example in Python

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

inc5 = makeInc(5)
inc10 = makeInc(10)

inc5 (5) # returns 10
inc10(5) # returns 15

Closures in python are created by function calls. Here, the call to makeInc creates a binding for x that is referenced inside the function inc. Each call to makeInc creates a new instance of this function, but each instance has a link to a different binding of x. The example shows the closure of x being used to eliminate either a global or a constant, depending on the nature of x.<ref>http://ynniv.com/blog/2007/08/closures-in-python.html Closures in Python</ref>

Statically typed languages, difficulty

We can explain this via an example. Method setBlock is defined as

|n|
...
b := [ n >= 0 ifTrue: ^1 ifFalse: ^0 ].

where b is an instance variable.After calling setBlock, a method of the same class may be called and may execute the above block - b value.

Inside the block there will be a return (^1 or ^0) from a method call of setBlock that no longer exists — a runtime error.
It seems impossible to add true closures to statically typed languages because of the above described run time errors.Although these errors may be considered as "type errors", they make the language unsafe which is against the norm of statically typed languages.<ref>http://dl.acm.org/citation.cfm?id=1026483 Guimar˜aes, Jos´e de Oliveira. "Closures for Statically-Typed Object-Oriented Languages"</ref>

  • Closures will need access to the lexical scope, ie, the scope in which the routine was generated as mentioned above. This is a problem for statically typed languages as they keep track of local variables in the stack. Once those variables go out of scope and the routine tries to access them, it will throw an exception. This problem must be overcome as closures must have access to that environment, even when it's out of scope. <ref> http://en.wikipedia.org/wiki/Static_scope Static Scope</ref>
  • In addition, since they must be first class functions, ie, the ability to use them as a normal data type, the statically typed language must have a specific type defined for functions. In the case of Java and C#, the garbage collector must keep those objects around, as well as their associated lexical environments, until there are no remaining references to that object.

In statically typed languages

Some of the object oriented languages simulate some of the features of closures.

Example in C++

For example:

  • C++ defines function objects by overloading operator().They may be created at run time and may implicitly capture the state but they don't have the access to local variables as closures do.
  • Two proposals to introduce C++ language support for closures (both proposals call them lambda functions) are being considered by the C++ Standards Committee.The main difference between these proposals is that one stores a copy of all the local variables in a closure by default, and another stores references to original variables. Both provide functionality to override the default behavior. If some form of these proposals is accepted, one would be able to write
void foo(string myname) {
    typedef vector<string> names;
    int y;
    names n;
    // ...
    names::iterator i = std::find_if(n.begin(), n.end(), [&](const string& s) { 
            return s != myname && s.size() > y; 
        });
    // 'i' is now either 'n.end()' or points to the first string in 'n'
    // which is not equal to 'myname' and whose length is greater than 'y'
}

At least two C++ compilers, Visual C++ 2010 and GCC 4.5, already support this notation.<ref>http://en.wikipedia.org/wiki/Closure_%28computer_science%29#C.2B.2B_.28operator_overloading.29 Closure like implementation in C++</ref>

Example in Java

JAVA allows functionality similar to closures via anonymous classes; an anonymous class may refer to names in lexically enclosing classes, or read-only variables (marked as final) in the lexically enclosing method.

        class CalculationWindow extends JFrame {
        private volatile int result;
        ...
        public void calculateInSeparateThread(final URI uri) {
                // The expression "new Runnable() { ... }" is an anonymous class.
                new Thread(
                        new Runnable() {
                                void run() {
                                        // It can read final local variables:
                                        calculate(uri);
                                        // It can access private fields of the enclosing class:
                                        result = result + 10;
                                }
                        }
                ).start();
        }
        }


Some features of full closures can be emulated by using a final reference to a mutable container, for example, a single-element array. The inner class will not be able to change the value of the container reference itself, but it will be able to change the contents of the container. <ref>http://en.wikipedia.org/wiki/Closure_%28computer_science%29#Java Closures like implementation in Java</ref>

Closures and Static Scoping

Static scoping (also known as Lexical scoping) is a property of the runtime text and is independent of the runtime call stack. <ref>http://en.wikipedia.org/wiki/Static_scope Static Scope</ref> Implementing closures in a statically scoped language can be very challenging.

  • It requires each function to maintain the variables in the scope in which the closure was declared, even after they have dropped out of scope.
  • When using static scoping languages that implement closures there is some question as to whether to have access to the actual mutable variable or to a copy of the value at the time it was declared. In other words, do we close over variables or values? This is something that developers must ascertain when using closures.

For example in Ruby if we have this code:

 $arr = Array.new
 def funcGen(val)
   0.upto(val) do |i|
         $arr[i] = Proc.new{print i}
   end
 end
 funcGen(4)
 $arr.each do |val|
   val.call
 end


We will have an output similiar to this: 01234

It uses a copy of the value, not the variable.

However, in C# if we have code does something similiar:

   delegate void Func();
   class Program
   {
       static Func[] funcArr = new Func[4];
       static void Main(string[] args)
       {
           fillFunc(funcArr.Length); 
           for (int i = 0; i < funcArr.Length; i++) 
           { 
               funcArr[i](); 
           }
       }
       static void fillFunc(int count) 
       { 
           for (int i = 0; i < count; i++)
           { 
               funcArr[i] = delegate() { Console.Write("{0}", i); };      
           } 
       }
   }

We will have this output. 4444

The last value set in the environment is used. This means that in this case, it closes over the variable, not the value, whereas Ruby closes over the value. <ref>http://blogs.msdn.com/b/abhinaba/archive/2005/10/18/482180.aspx C# Anonymous methods</ref>

Scheme's way of handling

Scheme is one of the two main dialects of programming language LISP.It's design policy is to provide small core and powerful tools for language extension.Compactness and Elegance are some of the few features what made Scheme popular in various communities of researchers.

Scheme is lexically scoped like most of the modern programming languages.all possible variable bindings in a program unit can be analyzed by reading the text of the program unit without consideration of the contexts in which it may be called.

The key insights on how to introduce lexical scoping into a Lisp dialect were popularized in Sussman and Steele's 1975 Lambda Paper, "Scheme: An Interpreter for Extended Lambda Calculus" where they adopted the concept of the lexical closure.<ref>http://en.wikipedia.org/wiki/Scheme_(programming_language)#Lexical_scope Scheme </ref>

An example in Scheme

(define (makem)
   (define x 34)
   (list (lambda () (set! x (+ x 1)) x)
         (lambda () (set! x (+ x 1)) x))
)
(define f (car (makem)))
(define f2 (car (cdr (makem))))
> (f)
35
> (f2)
35            
> (f)
36
> (f)
37
>

<ref>http://stackoverflow.com/questions/5608325/how-do-closures-in-scheme-work Closures in scheme </ref>

References

<references />