CSC/ECE 517 Fall 2011/ch1 1c sj: Difference between revisions
mNo edit summary |
|||
(54 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
==Closure vs. Methods | ==A comparison of Closure vs. Methods== | ||
A [http://en.wikipedia.org/wiki/Closure_(computer_science) closure] can be defined as a [http://en.wikipedia.org/wiki/First_class_function 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 | A [http://en.wikipedia.org/wiki/Closure_(computer_science) closure] can be defined as a [http://en.wikipedia.org/wiki/First_class_function 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 [http://en.wikipedia.org/wiki/Method_(computer_programming) 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. | A [http://en.wikipedia.org/wiki/Method_(computer_programming) method] is a function associated with a [http://en.wikipedia.org/wiki/Class_(computer_programming) 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 [http://en.wikipedia.org/wiki/Static_binding static binding], or at run time, which is a [http://en.wikipedia.org/wiki/Dynamic_dispatch dynamic binding]. | ||
===Examples of Closures vs. Methods=== | ===Examples of Closures vs. Methods=== | ||
In order to differentiate between the two, here are two examples that produce the same result: | In order to differentiate between the two, here are two code examples that produce the same result: | ||
Example 1: Closure (Ruby example) | ====Example 1: Closure ([http://www.ruby-lang.org/en/ Ruby] example)==== | ||
times = ['a', 'b', 'c'].collect {|item| item.upcase} | times = ['a', 'b', 'c'].collect {|item| item.upcase} | ||
Line 17: | Line 17: | ||
Example 2: Method (C++ style) | ====Example 2: Method ([http://en.wikipedia.org/wiki/C%2B%2B C++ style])==== | ||
class someObject() { | class someObject() { | ||
Line 38: | Line 38: | ||
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, but consider the following example: | 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 ([http://www.ruby-lang.org/en/ Ruby])==== | |||
The following code will test if an employee is also manager. | |||
def managers(emps) | def managers(emps) | ||
Line 50: | Line 51: | ||
Example 4: Method (C++ style) | ====Example 4: Method ([http://en.wikipedia.org/wiki/C%2B%2B 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) { | public static IList Managers(IList emps) { | ||
Line 56: | Line 59: | ||
foreach(Employee e in emps) | foreach(Employee e in emps) | ||
if (e.IsManager) result.Add(e); | 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. | 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==== | ====A note on [http://en.wikipedia.org/wiki/Anonymous_functions Anonymous Functions]==== | ||
Consider the following JavaScript function: | Consider the following [http://en.wikipedia.org/wiki/JavaScript JavaScript] function: | ||
function helloWorld() { | function helloWorld() { | ||
Line 83: | Line 85: | ||
} | } | ||
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. | 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:=== | ===Mimicking closures in other languages:=== | ||
Line 90: | Line 91: | ||
JavaScript has native support of closures. In fact, closures can be set up in JavaScript without even realizing that they’ve happened: | 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 name="buttonForm"> | ||
Line 111: | Line 114: | ||
</script> | </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 | 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) { | button.onclick = (function (e) { | ||
Line 121: | Line 126: | ||
})(i); | })(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. | 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. ''[http://books.google.com/books?id=PXa2bby0oQ0C 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() { | public void createButtons() { | ||
Line 148: | Line 155: | ||
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: | 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:''' | |||
Line 158: | Line 166: | ||
for (i = 1; i <= 5; i++) { | 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 | 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: | Also, having an anonymous inner class isn’t even necessary for this work; a regular inner class would be just as effective: | ||
Line 173: | Line 181: | ||
} | } | ||
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 | 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 be | 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:''' | |||
Line 198: | Line 207: | ||
===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== | |||
*http://www.javascriptkit.com/javatutors/closures.shtml | |||
*http://www.ibm.com/developerworks/opensource/library/os-php-5.3new2/index.html | |||
*http://stackoverflow.com/questions/111102/how-do-javascript-closures-work | |||
*http://pawelzubkiewicz.blogspot.com/2009/06/poors-man-closures-in-java.html | |||
*http://ivan.truemesh.com/archives/000392.html | |||
*http://nathansjslessons.appspot.com/lesson?id=1050&lang=en | |||
*http://zadasnotes.blogspot.com/2010/10/leaky-ie-javascript-closures.html | |||
*http://sleeplessgeek.blogspot.com/2009/12/so-what-are-these-closure-thingys.html | |||
*http://innig.net/software/ruby/closures-in-ruby.rb | |||
*http://blog.morrisjohns.com/javascript_closures_for_dummies.html | |||
Latest revision as of 02:35, 16 September 2011
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
- http://www.javascriptkit.com/javatutors/closures.shtml
- http://www.ibm.com/developerworks/opensource/library/os-php-5.3new2/index.html
- http://stackoverflow.com/questions/111102/how-do-javascript-closures-work
- http://pawelzubkiewicz.blogspot.com/2009/06/poors-man-closures-in-java.html
- http://ivan.truemesh.com/archives/000392.html
- http://nathansjslessons.appspot.com/lesson?id=1050&lang=en
- http://zadasnotes.blogspot.com/2010/10/leaky-ie-javascript-closures.html
- http://sleeplessgeek.blogspot.com/2009/12/so-what-are-these-closure-thingys.html
- http://innig.net/software/ruby/closures-in-ruby.rb
- http://blog.morrisjohns.com/javascript_closures_for_dummies.html