CSC/ECE 517 Fall 2011/ch1 1c sj

From Expertiza_Wiki
Jump to navigation Jump to search

A comparison of Closure vs. Methods

A closure can be defined as a First-Class function that retains the variables and values it references, even when the original variables and values go out of scope. Depending on the implementation and the language, a closure will either have the variables passed in by value (ie. each closure will have it’s own individual variables) or by reference (ie. each closure will share a reference to ONE variables).<ref>http://en.wikipedia.org/wiki/Closure_(computer_science)</ref> Differences between languages will be discussed in the second portion of this article.

A method is a function associated with a class. Methods have access to data stored in the class instance they are associated with and are able to act on that instance of the class. Methods can be bound to a class at compile time, which is a static binding, or at run time, which is a dynamic binding.

Examples of Closures vs. Methods

In order to differentiate between the two, here are two code examples that produce the same result:

Example 1: Closure (Ruby example)

 times = ['a', 'b', 'c'].collect {|item| item.upcase}
 puts times.join(", ") + " easy as 1, 2, 3."

Result → A, B, C easy as 1, 2, 3.


Example 2: Method (C++ style)

 class someObject() {
    void easyAs(String[] values)  {
       String final = "";
       for (int i = 0; i < values.size; i++)  {
          final += values[i].toupper();
          if ( i < values.size - 1)
            final += “, “;
       }
       final += “ easy as 1, 2, 3.”;
       cout << final;
    }
 }
 someObject obj = new someObject();
 String[] s = {“a”, “b”, “c”};
 obj.easyAs(a);

Result → A, B, C easy as 1, 2, 3.


The above examples show the closure method is much more concise and easier to read. Both pieces of code take an array of strings, process them, and print out a single string → “A, B, C easy as 1, 2, 3.”

At first glance this may look like syntactic sugar,<ref>http://www.ibm.com/developerworks/java/library/j-cb01097/index.html</ref> but consider the following example:

Example 3: Closure (Ruby)

The following code will test if an employee is also manager.

def managers(emps)
 return emps.select {|e| e.isManager}
end


Example 4: Method (C++ style)

The following is a C++ method that will do the same test to see if an employee is a manager.

public static IList Managers(IList emps) {
   IList result = new ArrayList();
   foreach(Employee e in emps)
     if (e.IsManager) result.Add(e);
   return result;
}

In this example, three lines of Ruby code (closure construct) replicates the method that would need to be embeded in an object that held a list of all employees. The savings in code writing extends far beyond just the size of these two methods.<ref>http://www.martinfowler.com/bliki/Closure.html</ref>

A note on Anonymous Functions

Consider the following JavaScript function:

function helloWorld() {
  return function() {
     alert("Hello World");
  }
}

The returned function in this case is anonymous but not a closure.

Now look at the following JavaScript function:

 function helloWorld() {
  var a = "Hello World";
  return function() {
     alert(a);
  }
 }

In this case, the returned function is a closure because it refers to helloWorlds's local variable a and causes the lifetime of a to extend beyond the normal scope of a, which is the helloWorld() function. The returned function "closes over" the variables in helloWorld() and have access to that local environment, even after the outer function goes out of scope.<ref>http://hendryluk.wordpress.com/2008/05/17/anonymous-method-is-not-closure/</ref>

Mimicking closures in other languages:

JavaScript has native support of closures. In fact, closures can be set up in JavaScript without even realizing that they’ve happened:

Example 1.

      <form name="buttonForm">
      </form>
      <script>
          function createButtons() {
              var i;
              var button;
              for (i = 1; i <= 5; i += 1) {
                  button = document.createElement("input");
                  button.type = "button";
                  button.id = "b" + i;
                  button.value = "button " + i;
                  button.onclick = function() {
                      alert("button " + i);
                  }
                  document.forms.buttonForm.appendChild(button);                
              }
          }
          createButtons();
      </script>

In this example, a closure is created when the onclick attribute of each button is set to an anonymous function that references the variable i in the createButtons function. The intention here is that clicking any of the buttons will result in an alert that displays “button x” where x is the number of the button. Unfortunately, this actually results in “button 6” being displayed for each button.

The reason for this is that i in the anonymous function is a reference to the i declared in createButtons, so clicking any of the buttons gives us the latest value of i rather than the value of i at the time the anonymous function was created. To get around this requires a more sophisticated function:

Example 2.

                  button.onclick = (function (e) {
                      return function() {
                          alert("button " + e);
                      }
                  })(i);

Now the alert no longer references i directly, but instead references a local parameter that has been set to the value of i at the time the function was created. The outer function is evoked immediately, but returns a function that has a closure on the local parameter. Unlike i, this value won’t change.<ref>Douglas Crockford. JavaScript: The Good Parts. O'Reilly Media, Inc.; 2008. ISBN 978-0-596-51774-8.</ref>

It’s been said that closures can be approximated in Java using anonymous inner classes.<ref>http://rickyclarkson.blogspot.com/2007/10/why-java-needs-closures-it-already-has.html</ref> If that’s the case, then we should be able to mimic both of the behaviors here, that is, we should be able to create buttons that refer to either the latest value of a variable like example 1, or have each button refer to the value of that variable at creation time like example 2. The first attempt at a createButtons function in Java similar to the one in the JavaScript examples might look like this:

Example 3.

  public void createButtons() {
      final int WIDTH = 50;
      for (int i = 1; i <= 5; i++) {
          JButton button = new JButton("Button " + i);
          button.setBounds(WIDTH * 2 * (i - 1) + WIDTH, 50, WIDTH * 2, 25);
          button.addActionListener(new ActionListener() {
              @Override
              public void actionPerformed(ActionEvent event) {
                  // This next statement results in a compile time error.
                  JOptionPane.showMessageDialog(panel, "Button " + i,
                          "Button Info", JOptionPane.INFORMATION_MESSAGE);
              }
          });
          panel.add(button);
      }
  }

Unfortunately, as indicated by the comment, this results in a compile time error:

   local variable i is accessed from within inner class; needs to be declared final

The problem with this, however, is that i cannot be final because its value need to change in order for the for loop to work correctly. There are two workarounds:

Workaround 1.

Make i an instance variable:


       private int i;
       ...
       public void createButtons() {
          final int WIDTH = 50;
          for (i = 1; i <= 5; i++) {

This does mimic the behavior of the first example, but in a very dissatisfying way. Before, i was only available within the scope of the for loop, but now it’s available to the entire object. This is rather disconcerting because it means that elements of the object other than the buttons can access i, potentially changing its value.

Also, having an anonymous inner class isn’t even necessary for this work; a regular inner class would be just as effective:

  button.addActionListener(new ButtonListener());
  ...
  private class ButtonListener implements ActionListener {
     @Override
      public void actionPerformed(ActionEvent e) {
          // This still works just fine.
          JOptionPane.showMessageDialog(panel, "Button " + i,
                      "Button Info", JOptionPane.INFORMATION_MESSAGE);
      }
  }

This clearly indicates that we no longer have any type of closure at all, but are simply using standard OOP. A slightly better option might be to subclass JButton and create a private static instance variable that can be set to the value of i, but we can’t allow createButtons to set this variable without letting any method in the object set the variable.<ref>http://www.zetcode.com/tutorials/javaswingtutorial/swingevents/</ref>

From this we see that the type of closure demonstrated in the first example cannot effectively be mimicked in Java without giving the rest of the object access to the variables in the closure as well.

Workaround 2.

Set some other variable equal to i and make that variable final:


          ...
          // Need this for closure to work
          final int j = i;
          button.addActionListener(new ActionListener() {
              @Override
              public void actionPerformed(ActionEvent event) {
                  // Now this works fine.
                  JOptionPane.showMessageDialog(panel, "Button " + j,
                          "Button Info", JOptionPane.INFORMATION_MESSAGE);
              }
          });

It turns out that this is a good match to the second JavaScript example. Each button has access to the value of i at the time the closure was created. Since this was also the desired behavior, then it appears using an anonymous class can be used to effectively mimic closures in at least some circumstances.

Note, however, that setting up a closure this way in JavaScript was actually a bit more convoluted. It seems likely that the type of closure given in the first example is actually much more common, and this is the type of closure that Java has difficulty in handling. This means that the closure pattern will not be available for many cases where it might be useful in Java, and likely in other languages as well.


Conclusion:

Based on the examples given, there are instances where closures are either more convenient to use than traditional methods, or provide better encapsulation of private information. While this doesn't necessarily mean that closures should be natively added to languages that don't fully support them,<ref>http://www.oreillynet.com/onjava/blog/2006/08/will_we_have_closures_in_java.html</ref> there is a good place for them in dynamic languages such as Ruby and JavaScript, as well extensions of static languages such as Groovy.<ref>http://groovy.codehaus.org/Closures</ref>

References

<references />

Additional Resources