Closures in Groovy work naturally and are entirely effective. They soon predominate the way one codes in Groovy and really is the hallmark characteristic feature of this language.
Closure proposals for the Java language all stink.
Other proposed Java language features, such as xml literals, also stink. Groovy XML markup is a much superior concept.
AspectJ is far too much down a AOP rabbit hole for most people to stomach. (I rather like what can be done with AspectJ and love using its power for patching 3rd party libraries - but would be first to admit it'll never catch on as mainstream.) Alternatively, adding new methods in an AOP-like (or C# extensions methods-like manner) to existing classes using Groovy is painless, as is the gamut of meta programming features in Groovy.
LINQ has turned C# into a bloated PL/1 language monstrosity - now looks like a public works project for language designers. (One can tell C# has now fallen into the disrepute of bloat-ware by looking at the C# 2.0 addition of anonymous delegates. This feature is entirely dissatisfying to use. They're throwing in features without much regard for what it will be like in practice to use those features.) In contrast the Groovy feature to convert closures of Groovy language into equivalent SQL expression is light weight and satisfying. A good balance has been struck.
I've merely scratched the surface of examples, but my point is that Groovy is already the next evolutionary iteration of the Java language. There is no need to add any new features to Java as doing so will fall into the same quagmire that C# 2.0/3.0 have fallen into. Groovy already has some feature or characteristic that addresses nearly every point of critique that has been leveled at Java the language over the last five or so years.
Wow. Do you earn money everytime a soul converts to Groovy? I mean, talk about a pitch....
Not that you're basically right. Groovy's take on closures is pretty neat.
However, groovy isn't java. What it is, is very compatible with java. Which means java needs the very niche I've always advocated: Typing, Typing, Typing, and more Typing, to a fault.
So bring on the NonNull types. Make n-tuple generics possible. Give us CICE (because it types far more than BGGA (Gafter's) closures). If typing is more useful for a given project, then you're already going to go with java, whereas if typing isn't your cup of tea, picking java is a mistake in the first place.
However, what you're proposing is tantamount to declaring Groovy to be equal to java 1.8, and essentially @Deprecating java. That's a bit much, not?
Re: Your analysis that C# is well on its way to becoming perl soup: Good eye. Absolutely true.
On Mar 17, 10:38 pm, "RogerV" <rog...@qwest.net> wrote:
> Closures in Groovy work naturally and are entirely effective. They > soon predominate the way one codes in Groovy and really is the > hallmark characteristic feature of this language.
> Closure proposals for the Java language all stink.
> Other proposed Java language features, such as xml literals, also > stink. Groovy XML markup is a much superior concept.
> AspectJ is far too much down a AOP rabbit hole for most people to > stomach. (I rather like what can be done with AspectJ and love using > its power for patching 3rd party libraries - but would be first to > admit it'll never catch on as mainstream.) Alternatively, adding new > methods in an AOP-like (or C# extensions methods-like manner) to > existing classes using Groovy is painless, as is the gamut of meta > programming features in Groovy.
> LINQ has turned C# into a bloated PL/1 language monstrosity - now > looks like a public works project for language designers. (One can > tell C# has now fallen into the disrepute of bloat-ware by looking at > the C# 2.0 addition of anonymous delegates. This feature is entirely > dissatisfying to use. They're throwing in features without much regard > for what it will be like in practice to use those features.) In > contrast the Groovy feature to convert closures of Groovy language > into equivalent SQL expression is light weight and satisfying. A good > balance has been struck.
> I've merely scratched the surface of examples, but my point is that > Groovy is already the next evolutionary iteration of the Java > language. There is no need to add any new features to Java as doing so > will fall into the same quagmire that C# 2.0/3.0 have fallen into. > Groovy already has some feature or characteristic that addresses > nearly every point of critique that has been leveled at Java the > language over the last five or so years.
In 2.0 and 3.0 definitions of that language, many new features have been added. Some of them cover turf that is being contemplated for Java.
Am concerned that trying to accommodate some of these popular language features might not be possible to do with sufficient grace in a strongly typed language.
Groovy is not held back by that predicament as is Java. It permits typed variables, but they are optional. Groovy code can thus be written with conciseness and grace.
>From experience of using C#, have begun to ponder if Java 5 is far
enough to take a strongly typed language.
Yet maybe am completely wrong about this. Maybe a new strongly typed language could be created that has these cool concepts, yet is a graceful language to write in. It might be that C# and Java are both just encumbered by their respective baggage.
> Yet maybe am completely wrong about this. Maybe a new strongly typed > language could be created that has these cool concepts, yet is a > graceful language to write in. It might be that C# and Java are both > just encumbered by their respective baggage.
What's the clumsy part of C#'s type inferencing system or lambda functions? It is still very much a statically typed language if you ask me. Post-generics collection classes, int pseudo-enums and code labels are examples of non-graceful things in my book.
I find this debate ironic. I've been a long time user of BeanShell -- another loosely typed Java-based language that allows prototyping and had autoboxing before Java did. In general though, it's hailed as a Java superset. It's pretty neat to see what people do with it. Anyway, one of the things that have come up on the BeanShell discussion board lately is the feature request to be able to preload scripts and verify their integrity. Obviously, since it's a dynamic language, it's not the easiest thing in the world to do. And here, we've have Java-heads asking for dynamic language features. I think we've got it already. We have dynamic languages that can interface with JVM and load Java libraries. Therefore, we can distribute code to and from the dynamic environment as we see fit.
In 2.0 and 3.0 definitions of that language, many new features have been added. Some of them cover turf that is being contemplated for Java.
Am concerned that trying to accommodate some of these popular language features might not be possible to do with sufficient grace in a strongly typed language.
Groovy is not held back by that predicament as is Java. It permits typed variables, but they are optional. Groovy code can thus be written with conciseness and grace.
>From experience of using C#, have begun to ponder if Java 5 is far
enough to take a strongly typed language.
Yet maybe am completely wrong about this. Maybe a new strongly typed language could be created that has these cool concepts, yet is a graceful language to write in. It might be that C# and Java are both just encumbered by their respective baggage.
Casper, was going to concede that C# type inference var declaration does indeed pan out as graceful. Used with tuples (anonymous classes), this feature all seems to work out - while preserving strong typing! To my knowledge, though, this is one cool feature item of C# that I don't think anyone in Java community has paid attention to.
Not sure yet on lambda functions. My reaction in watching C# compiler guys showing off code examples utilizing this, was that things started to turn esoteric. BTW, is the bulk of the Java programming community ready to go down the functional programming rabbit hole? Is the concept of currying, et al, ready for the mainstream?
Now I was at first excited about anonymous delegates, but the experience of trying to use that feature has rather soured me on them. This is just a stark example of adding something to a language that was a good idea on paper but stinks in practice. It is exactly this that am fearful for Java in regard to closures.
On Mar 19, 1:37 pm, "Casper Bang" <c...@brunata.dk> wrote:
> > Yet maybe am completely wrong about this. Maybe a new strongly typed > > language could be created that has these cool concepts, yet is a > > graceful language to write in. It might be that C# and Java are both > > just encumbered by their respective baggage.
> What's the clumsy part of C#'s type inferencing system or lambda > functions? It is still very much a statically typed language if you > ask me. Post-generics collection classes, int pseudo-enums and code > labels are examples of non-graceful things in my book.
public final void calculateInSeparateThread(final URI uri) { // The expression "new Runnable() { ... }" is an anonymous class. Runnable runner = new Runnable() { void run() { // It can access final local variables: calculate(uri); // It can access private fields of the enclosing class: // Always update the Graphic components into the Swing Thread SwingUtilities.invokeLater(new Runnable() { public void run() { btnSave.setEnabled(true); } }); } }; new Thread(runner).start(); }
Casper, was going to concede that C# type inference var declaration does indeed pan out as graceful. Used with tuples (anonymous classes), this feature all seems to work out - while preserving strong typing! To my knowledge, though, this is one cool feature item of C# that I don't think anyone in Java community has paid attention to.
Not sure yet on lambda functions. My reaction in watching C# compiler guys showing off code examples utilizing this, was that things started to turn esoteric. BTW, is the bulk of the Java programming community ready to go down the functional programming rabbit hole? Is the concept of currying, et al, ready for the mainstream?
Now I was at first excited about anonymous delegates, but the experience of trying to use that feature has rather soured me on them. This is just a stark example of adding something to a language that was a good idea on paper but stinks in practice. It is exactly this that am fearful for Java in regard to closures.
On Mar 19, 1:37 pm, "Casper Bang" wrote:
> > Yet maybe am completely wrong about this. Maybe a new strongly typed > > language could be created that has these cool concepts, yet is a > > graceful language to write in. It might be that C# and Java are both > > just encumbered by their respective baggage.
> What's the clumsy part of C#'s type inferencing system or lambda > functions? It is still very much a statically typed language if you > ask me. Post-generics collection classes, int pseudo-enums and code > labels are examples of non-graceful things in my book.
Just between you and me, Alexey, I'm rather with you on that. Anonymous inner classes do rather meet the "walks like a duck, quacks like a duck" manner of test. And as far as so-called Java closures go, I'd vote to leave it right there. Things start getting weird in Java when going beyond this point.
If you think about it, the current approach of implementing method(s) on an interface is an ideal way to deal with issues such as Java's checked exceptions (ah, is no different than for any regular method - well, because it's just a method too). And I've never found declaring some locals as final an onerous problem in order for them to become so- called "member variables" of the generated anonymous inner class.
> public final void calculateInSeparateThread(final URI uri) { > // The expression "new Runnable() { ... }" is an anonymous class. > Runnable runner = new Runnable() { > void run() { > // It can access final local variables: > calculate(uri); > // It can access private fields of the enclosing class: > // Always update the Graphic components into the Swing Thread > SwingUtilities.invokeLater(new Runnable() { > public void run() { > btnSave.setEnabled(true); > }
> }); > } > }; > new Thread(runner).start(); > }
But this is taken from the "Closure-like constructs in other languages" section of the article. Anonymous inner classes, while useful, are not closures. Neal Gafter provides a great explanation of why here:
Call me dense, but I still don't understand. His main problems with anonymous classes are:
Verbose, extra wordy (isn't that what verbose means?), clumsy, redundant -- syntax sugar.
Incomplete capture of lexical context -- one man's explicit declaration of what free variables the anonymous class refers to is another man's incomplete capture of lexical context I guess. I see nothing wrong with using EnclosingClass.this.foo. Also, much of his pains with return types and exception throwing is just a matter of properly laying out your API. Something we should strive for regardless.
Control abstraction not possible -- yes it is. It's just a matter of how you lay out your API. All he's saying is he doesn't wanna have to write generic enough interfaces that encompass exception handling and return types. Here's an example:
I've created a BeanShell-based Java spreadsheet. BeanShell is a Java syntax superset, so the BeanShell code will be obvious to everyone here. A spreadsheet is by its very nature a kind of functional language environment, something that relies on closures heavily. Immediately, I realized I had a need for a closure-like construct. I did not want to much with the syntax if I could help it. I did have a concept of cell ranges expressed as an iterator of their addresses. A typical use of a closure here would be to express subrange selection in an each-member-such-that way. I therefore created a conditional iterator that took a condition object. All I had to do then was create an evaluated expression condition implementation that took a string value signifying some expression that got evaluated:
public class InterpretedCondition implements ConditionalIterator.Condition { protected final BSHTableModel model; protected final String expression;
This statement adds numbers within the range of c10:c200 that are next to a cell ( deref(val, 1, 0) ) containing the text that's next to the cell we're in ( [-1-0] ). Much the same code can be used within compiled Java itself, minus the special cell reference syntax of course. We can throw the same exceptions. We can return early. We can do all the same stuff this guy is complaining about being difficult without changing the language. I get the feeling he wants a functional language, which Java isn't. But he can have things closer to functional languages thanks to the multitude of different dynamic languages available today that integrate with JVM. I believe there's even a project for porting Haskel to JVM. So I really don't see a need for modifying the Java language itself.
"J. McConnell" <jdo...@gmail.com> wrote: On 3/19/07, Alexey Zinger <inline_f...@yahoo.com> wrote: I don't get it. Don't we have closure functionality in Java now via anonymous classes? From Wikipedia page on closures < http://en.wikipedia.org/wiki/Closure_%28computer_science%29>:
public final void calculateInSeparateThread(final URI uri) { // The expression "new Runnable() { ... }" is an anonymous class.
Runnable runner = new Runnable() { void run() { // It can access final local variables: calculate(uri); // It can access private fields of the enclosing class:
// Always update the Graphic components into the Swing Thread SwingUtilities.invokeLater(new Runnable() { public void run() {
btnSave.setEnabled(true); }
}); } }; new Thread(runner).start(); }
But this is taken from the "Closure-like constructs in other languages" section of the article. Anonymous inner classes, while useful, are not closures. Neal Gafter provides a great explanation of why here:
You can have your cake (consider anonymous classes java's closures) and eat it too (reduce verbiage and make that "final" stuff easier to handle):
CICE is an alternative closure proposal that is just some light syntactic sugaring over what's already there. I think this is the single greatest improvement to the java language that can possibly be made:
> Call me dense, but I still don't understand. His main problems with anonymous classes are:
> Verbose, extra wordy (isn't that what verbose means?), clumsy, redundant -- syntax sugar.
> Incomplete capture of lexical context -- one man's explicit declaration of what free variables the anonymous class refers to is another man's incomplete capture of lexical context I guess. I see nothing wrong with using EnclosingClass.this.foo. Also, much of his pains with return types and exception throwing is just a matter of properly laying out your API. Something we should strive for regardless.
> Control abstraction not possible -- yes it is. It's just a matter of how you lay out your API. All he's saying is he doesn't wanna have to write generic enough interfaces that encompass exception handling and return types. Here's an example:
> I've created a BeanShell-based Java spreadsheet. BeanShell is a Java syntax superset, so the BeanShell code will be obvious to everyone here. A spreadsheet is by its very nature a kind of functional language environment, something that relies on closures heavily. Immediately, I realized I had a need for a closure-like construct. I did not want to much with the syntax if I could help it. I did have a concept of cell ranges expressed as an iterator of their addresses. A typical use of a closure here would be to express subrange selection in an each-member-such-that way. I therefore created a conditional iterator that took a condition object. All I had to do then was create an evaluated expression condition implementation that took a string value signifying some expression that got evaluated:
> public class InterpretedCondition implements ConditionalIterator.Condition > { > protected final BSHTableModel model; > protected final String expression;
> This statement adds numbers within the range of c10:c200 that are next to a cell ( deref(val, 1, 0) ) containing the text that's next to the cell we're in ( [-1-0] ). Much the same code can be used within compiled Java itself, minus the special cell reference syntax of course. We can throw the same exceptions. We can return early. We can do all the same stuff this guy is complaining about being difficult without changing the language. I get the feeling he wants a functional language, which Java isn't. But he can have things closer to functional languages thanks to the multitude of different dynamic languages available today that integrate with JVM. I believe there's even a project for porting Haskel to JVM. So I really don't see a need for modifying the Java language itself.
> "J. McConnell" <jdo...@gmail.com> wrote: On 3/19/07, Alexey Zinger <inline_f...@yahoo.com> wrote: I don't get it. Don't we have closure functionality in Java now via anonymous classes? From Wikipedia page on closures <http://en.wikipedia.org/wiki/Closure_%28computer_science%29>:
> public final void calculateInSeparateThread(final URI uri) { > // The expression "new Runnable() { ... }" is an anonymous class.
> Runnable runner = new Runnable() { > void run() { > // It can access final local variables: > calculate(uri); > // It can access private fields of the enclosing class:
> // Always update the Graphic components into the Swing Thread > SwingUtilities.invokeLater(new Runnable() { > public void run() {
> btnSave.setEnabled(true); > }
> }); > } > }; > new Thread(runner).start(); > }
> But this is taken from the "Closure-like constructs in other languages" section of the article. Anonymous inner classes, while useful, are not closures. Neal Gafter provides a great explanation of why here:
> You can have your cake (consider anonymous classes java's closures) > and eat it too (reduce verbiage and make that "final" stuff easier to > handle):
> CICE is an alternative closure proposal that is just some light > syntactic sugaring over what's already there. I think this is the > single greatest improvement to the java language that can possibly be > made:
I'm familiar with CICE and I would be happy to have CICE over nothing, but the fact is that anonymous inner classes are not closures for the reasons Gafter puts forward, so CICE doesn't give Java closures. Although I would find CICE useful, I think it would be a mistake to go half-way with closures support. If you are going to pull in much of the syntax anyway for CICE, why not bring in the other supporting functionality that BGGA requires like function types and a null type?
The arguments I've heard so far pretty much boil down to the fact that it just complicates the language too much. Complicates it for who? It might complicate it some for API writers, but don't you want them to be pretty capable anyway? Shouldn't API writers be familiar enough with a language to take advantage of all the tools it provides? The clients of such an API written to support closures wouldn't need to know any more than they would to take advantage of CICE in the vast majority of cases.
Contrast this complication with the Java Security Model. Now, my understanding is that that thing is a mess (I'm sure necessarily so) that I wouldn't even take the time to understand unless I had a specific reason to do so. That doesn't keep me from understanding Java at all, though. Nor does it keep me from benefiting from some of the safety nets put in place by the JSM. I think closures, as proposed in BGGA, are similarly complicated for a few but simple for many.
On 3/20/07, Alexey Zinger <inline_f...@yahoo.com> wrote:
> Call me dense, but I still don't understand. His main problems with > anonymous classes are:
> Verbose, extra wordy (isn't that what verbose means?), clumsy, redundant-- syntax sugar.
Sure there's a dose of syntax sugar, but it does sweeten up a bunch of use cases, so might it be worth it? Don't just dismiss it because it's syntax sugar. The new for loop is just syntax sugar, but I don't see how that alone would have been a reason not to include it.
Incomplete capture of lexical context -- one man's explicit declaration of
> what free variables the anonymous class refers to is another man's > incomplete capture of lexical context I guess. I see nothing wrong with > using EnclosingClass.this.foo.
As Neal points out, there are many more language constructs in Java that make up the lexical context than just variable names. A good example is "The referent of a return statement." He actually points out that the incorrect scoping of variable names is the least significant fault with anonymous inner classes, as far as them being closures goes.
Also, much of his pains with return types and exception throwing is just a
> matter of properly laying out your API. Something we should strive for > regardless.
What problems are these? I couldn't find what you were referring you.
Control abstraction not possible -- yes it is.
No, it's not.
It's just a matter of how you lay out your API. All he's saying is he
> doesn't wanna have to write generic enough interfaces that encompass > exception handling and return types.
No, what he's saying is that he doesn't want to write interfaces at all, but rather the equivalent of language-level control constructs.
> I've created a BeanShell-based Java spreadsheet. BeanShell is a Java > syntax superset, so the BeanShell code will be obvious to everyone here. A > spreadsheet is by its very nature a kind of functional language environment, > something that relies on closures heavily. Immediately, I realized I had a > need for a closure-like construct. I did not want to much with the syntax > if I could help it. I did have a concept of cell ranges expressed as an > iterator of their addresses. A typical use of a closure here would be to > express subrange selection in an each-member-such-that way. I therefore > created a conditional iterator that took a condition object. All I had to > do then was create an evaluated expression condition implementation that > took a string value signifying some expression that got evaluated:
> public class InterpretedCondition implements ConditionalIterator.Condition > { > protected final BSHTableModel model; > protected final String expression;
> This statement adds numbers within the range of c10:c200 that are next to > a cell ( deref(val, 1, 0) ) containing the text that's next to the cell > we're in ( [-1-0] ). Much the same code can be used within compiled Java > itself, minus the special cell reference syntax of course. We can throw the > same exceptions. We can return early. We can do all the same stuff this > guy is complaining about being difficult without changing the language. I > get the feeling he wants a functional language, which Java isn't. But he > can have things closer to functional languages thanks to the multitude of > different dynamic languages available today that integrate with JVM. I > believe there's even a project for porting Haskel to JVM. So I really don't > see a need for modifying the Java language itself.
First off, let me say that this is fine code. I don't have any problem with the code, but there's no control abstraction going on here. What you aren't showing us here is the implementation of "sum", "condition" and "ConditionalIterator". The "sum" method probably looks something like:
public double sum(Iterator iter) { double sum = 0; for (iter; iter.hasNext(); ) { Cell c = (Cell) iter.next(); sum += c.getCellValue(); } return sum;
}
What control construct does this code use? It uses a "for" loop. Why? Because you don't have any other options in Java, so you need to fake out a conditional for loop by using a specialized Iterator. What closures would give you is the ability to write this method as such:
public double sum(List<Cell> cells, Condition condition) { double sum = 0; forEachSuchThat(cells, condition) (Cell c) { sum += c.getCellValue(); }
}
In essence here, you've created your own for loop that looks like and acts like a language-level control construct. This is what Gafter is referring to as "control abstraction".
J. McConnell wrote: > On 3/20/07, Alexey Zinger <inline_f...@yahoo.com> wrote:
>> Verbose, extra wordy (isn't that what verbose means?), clumsy, redundant-- syntax sugar.
> Sure there's a dose of syntax sugar, but it does sweeten up a bunch of use > cases, so might it be worth it? Don't just dismiss it because it's syntax > sugar. The new for loop is just syntax sugar, but I don't see how that > alone would have been a reason not to include it
Simple answer for all Closure (lambda function, anonymous function, ...) doubters: Everyone who has ever asked for a new for_with_index construct in Java, actually secretly wants Closures, just doesn't know it yet.
The Java 5 new for Loop is a hack, that handles one single special case, and quickly breaks down as soon as you want to do anything special. Eg. map, fold, select, ... the same things suffixed with "_index", etc. would all be possible _and_ nicely integrated with the language if Closures were around.
There's this old argument that higher level [dynamic] languages had problems because they weren't as suited towards refactoring... of course, any language with closures supports many more refactorings than Java. Eg. this code List results = new ArrayList(); for(Foo foo : results){ if(foo.foo()){ results.add(foo); }
}
This sucker is rife for refactoring, since it's redundant. The only significant code in there is the condition... the rest is boilerplate. In the code review process, it'd be nice to refactor this code to something concise like this: results = foo.collect{|x| x.foo() }
No overhead, no code duplication, no source for errors stemming from spreading similar code over your source base. Of course: only possible in a language with Closures. (Yeah, you could approximate that with Anonymous Functions, except that the code would then be littered with loads of useless clutter).
And: the readability stays the same... simply because the implementation of "collect" is just a Ctrl-Click away (assuming you use a proper IDE). There ain't no magic, unlike language features, where implementation semantics are hidden in the language spec/compiler.
Mind you: control flow or iteration constructs aren't the only use for this,... once you got the idea of parameterizing algorithms, you'll see opportunities everywhere.
"J. McConnell" <jdo...@gmail.com> wrote: On 3/20/07, Alexey Zinger <inline_f...@yahoo.com> wrote: Call me dense, but I still don't understand. His main problems with anonymous classes are:
Verbose, extra wordy (isn't that what verbose means?), clumsy, redundant -- syntax sugar. Sure there's a dose of syntax sugar, but it does sweeten up a bunch of use cases, so might it be worth it? Don't just dismiss it because it's syntax sugar. The new for loop is just syntax sugar, but I don't see how that alone would have been a reason not to include it.
The problem with syntax sugar is not that it lacks benefits. It's that the benefits often don't outweigh the costs if we start sliding down the slippery slope of modifying core language with every release to accommodate specific usage patterns. The new for loop is a very simple change that crosses nearly all conceivable usage patterns. In my opinion, implementing closures within the language just doesn't get "everyone" enough over what can be done with anonymous instances and things like AspectJ.
Incomplete capture of lexical context -- one man's explicit declaration of what free variables the anonymous class refers to is another man's incomplete capture of lexical context I guess. I see nothing wrong with using EnclosingClass.this.foo. As Neal points out, there are many more language constructs in Java that make up the lexical context than just variable names. A good example is "The referent of a return statement." He actually points out that the incorrect scoping of variable names is the least significant fault with anonymous inner classes, as far as them being closures goes.
"Incorrect", being in the sense of language theory. Language theory is really fun. But in essence, it's useless both in the context of pragmatism as well as dreaming up new concepts. When we talk about present and past technologies, fine, let's apply those methodologies. But when we look into the future, there are only 2 angles: what crazy new concepts can we come up with and what will it be to actually use? In both of those senses, what we know now or consider to be "correct" in isolation is irrelevant. In other words, saying we need closures because current features of the language aren't true closures is a circular argument. At least that's how I understand the situation.
Also, much of his pains with return types and exception throwing is just a matter of properly laying out your API. Something we should strive for regardless. What problems are these? I couldn't find what you were referring you.
I must apologize -- I've been feeling a little under the weather lately. I believe what I was referring to here is that Neal Gafter talks at great length about being able to return the right thing out of a closure. See slide 15. Maybe I'm not understanding correctly his point, but I see the issue as merely a question of correct API.
Control abstraction not possible -- yes it is. No, it's not.
See below.
It's just a matter of how you lay out your API. All he's saying is he doesn't wanna have to write generic enough interfaces that encompass exception handling and return types. No, what he's saying is that he doesn't want to write interfaces at all, but rather the equivalent of language-level control constructs.
See below still...
Here's an example:
I've created a BeanShell-based Java spreadsheet. BeanShell is a Java syntax superset, so the BeanShell code will be obvious to everyone here. A spreadsheet is by its very nature a kind of functional language environment, something that relies on closures heavily. Immediately, I realized I had a need for a closure-like construct. I did not want to much with the syntax if I could help it. I did have a concept of cell ranges expressed as an iterator of their addresses. A typical use of a closure here would be to express subrange selection in an each-member-such-that way. I therefore created a conditional iterator that took a condition object. All I had to do then was create an evaluated expression condition implementation that took a string value signifying some expression that got evaluated:
public class InterpretedCondition implements ConditionalIterator.Condition { protected final BSHTableModel model; protected final String expression;
This statement adds numbers within the range of c10:c200 that are next to a cell ( deref(val, 1, 0) ) containing the text that's next to the cell we're in ( [-1-0] ). Much the same code can be used within compiled Java itself, minus the special cell reference syntax of course. We can throw the same exceptions. We can return early. We can do all the same stuff this guy is complaining about being difficult without changing the language. I get the feeling he wants a functional language, which Java isn't. But he can have things closer to functional languages thanks to the multitude of different dynamic languages available today that integrate with JVM. I believe there's even a project for porting Haskel to JVM. So I really don't see a need for modifying the Java language itself. First off, let me say that this is fine code. I don't have any problem with the code, but there's no control abstraction going on here. What you aren't showing us here is the implementation of "sum", "condition" and "ConditionalIterator". The "sum" method probably looks something like:
public double sum(Iterator iter) { double sum = 0; for (iter; iter.hasNext(); ) { Cell c = (Cell) iter.next(); sum += c.getCellValue(); } return sum;
}
For reference, here's ConditionalIterator and sum code:
public class ConditionalIterator implements Iterator { public static interface Condition { public boolean isSatisfied(Object contextValue); }
protected final Iterator iterator; protected final ConditionalIterator.Condition condition;
public void remove() throws UnsupportedOperationException { throw new UnsupportedOperationException(); }
}
Ranges are actually represented by iterators of cell coordinates rather than cell values:
sum(iter) { sum = 0.0; while(iter.hasNext()) { val = iter.next(); model.requestDependency(val.x, val.y, col, row); val = model.evalValueAt(val.x, val.y); if(val != null && Number.class.isAssignableFrom(val.getClass())) { sum += val; } } return sum;
}
What control construct does this code use? It uses a "for" loop. Why? Because you don't have any other options in Java, so you need to fake out a conditional for loop by using a specialized Iterator. What closures would give you is the ability to write this method as such:
public double sum(List<Cell> cells, Condition condition) { double sum = 0; forEachSuchThat(cells, condition) (Cell c) { sum += c.getCellValue(); }
}
Yeah, and what's the difference other than verbosity (in setup, not much in client code)? There's no performance hit either way.
In essence here, you've created your own for loop that looks like and acts like a language-level control construct. This is what Gafter is referring to as "control abstraction".
Right. And my point is that if it's possible to "fake" these control mechanisms already without performance hits or some other hidden issues, why do we need a change to the language?
> On 3/20/07, Alexey Zinger <inline_f...@yahoo.com> wrote:
> > Call me dense, but I still don't understand. His main problems with > > anonymous classes are:
> > Verbose, extra wordy (isn't that what verbose means?), clumsy, redundant-- syntax sugar.
> Sure there's a dose of syntax sugar, but it does sweeten up a bunch of use > cases, so might it be worth it? Don't just dismiss it because it's syntax > sugar. The new for loop is just syntax sugar, but I don't see how that > alone would have been a reason not to include it.
> The problem with syntax sugar is not that it lacks benefits. It's that > the benefits often don't outweigh the costs if we start sliding down the > slippery slope of modifying core language with every release to accommodate > specific usage patterns. The new for loop is a very simple change that > crosses nearly all conceivable usage patterns. In my opinion, implementing > closures within the language just doesn't get "everyone" enough over what > can be done with anonymous instances and things like AspectJ.
Alright, well I can't argue with your opinion :) However, I would like to point out (as did murphee, I believe) that if Java had closures, the new for loop would have been unneccessary because you can implement the equivalent with closures. So, there's one big usage right there.
Incomplete capture of lexical context -- one man's explicit declaration of
> > what free variables the anonymous class refers to is another man's > > incomplete capture of lexical context I guess. I see nothing wrong with > > using EnclosingClass.this.foo.
> As Neal points out, there are many more language constructs in Java that > make up the lexical context than just variable names. A good example is > "The referent of a return statement." He actually points out that the > incorrect scoping of variable names is the least significant fault with > anonymous inner classes, as far as them being closures goes.
> "Incorrect", being in the sense of language theory. Language theory is > really fun. But in essence, it's useless both in the context of pragmatism > as well as dreaming up new concepts. When we talk about present and past > technologies, fine, let's apply those methodologies. But when we look into > the future, there are only 2 angles: what crazy new concepts can we come up > with and what will it be to actually use? In both of those senses, what we > know now or consider to be "correct" in isolation is irrelevant. In other > words, saying we need closures because current features of the language > aren't true closures is a circular argument. At least that's how I > understand the situation.
No one is saying that we need closures because anonymous inner classes aren't closures. People are saying we need closures because we want to do X, Y and Z, things like overhauling the Collections API to be much more usable. The only reason the closure supporters are pointing out that anonymous inner classes aren't closures is because those that aren't as familiar with closures claim that they are. In order to build support, it's necessary to point out this fallacy.
Also, much of his pains with return types and exception throwing is just a
> > matter of properly laying out your API. Something we should strive for > > regardless.
> What problems are these? I couldn't find what you were referring you.
> I must apologize -- I've been feeling a little under the weather lately. > I believe what I was referring to here is that Neal Gafter talks at great > length about being able to return the right thing out of a closure. See > slide 15. Maybe I'm not understanding correctly his point, but I see the > issue as merely a question of correct API.
No need to apologize, I've been sick myself. First, Gafter isn't complaining about return types, he's complaining about the fact that the return statement loses it's semantics inside anonymous inner classes, I believe in an effort to point out a problem with CICE that BGGA solves.
It's funny that a couple of times you have taken mine of Gafter's using of "incorrect" and pointed out, more or less, that it just depends on your frame of reference and then you argue a point by say that it is "merely a question of a correct API." Let's just say there's no such thing as a "correct" API. However, it's true you can get the same exact functionality that Gafter is talking about by refactoring the API. Of course you can! Java is Turing-complete. No one is arguing that. All Gafter is saying is "Here's the code I want to write, here's why I can't write it in Java, as-is, here's how I could write it in Java with closures." You can claim that the costs outweigh the benefits, but you can't claim that he can write what he wants without closures.
At this point I have a question. Have you ever had any serious experience with closures? If not, I can understand where you are coming from. They don't seem like the biggest deal in the world until you've actually used them for any significant period of time. For that reason, I feel this is an important question.
Control abstraction not possible -- yes it is.
> No, it's not.
> See below.
For reference, here's ConditionalIterator and sum code:
> In essence here, you've created your own for loop that looks like and acts > like a language-level control construct. This is what Gafter is referring > to as "control abstraction".
> Right. And my point is that if it's possible to "fake" these control > mechanisms already without performance hits or some other hidden issues, why > do we need a change to the language?
There are a few reasons. For one, not everything that you can do with closures can be as-easily faked out. Also, this code is not as easy to read as code written with a custom forEachSuchThat loop construct. The intention of the code is obscured somewhat by boilerplate. The boilerplate in this example is small, but it is still there (iter.hasNext(), iter.next(), etc.) Other examples have much more boilerplate, much of which can be done away with using closures.
> It's funny that a couple of times you have taken mine of Gafter's using of > "incorrect" and pointed out, more or less, that it just depends on your > frame of reference and then you argue a point by say that it is "merely a > question of a correct API." Let's just say there's no such thing as a
When I was talking about it being a matter of "correct API", I was referring specifically to finding the right solution to the problem at hand, considering specific abstractions and design patterns. However, when we talk about introducing changes to the language, we are forced to think in global terms.
> "correct" API. However, it's true you can get the same exact functionality > that Gafter is talking about by refactoring the API. Of course you can! > Java is Turing-complete. No one is arguing that. All Gafter is saying is > "Here's the code I want to write, here's why I can't write it in Java, > as-is, here's how I could write it in Java with closures." You can claim > that the costs outweigh the benefits, but you can't claim that he can write > what he wants without closures.
> At this point I have a question. Have you ever had any serious experience > with closures? If not, I can understand where you are coming from. They > don't seem like the biggest deal in the world until you've actually used > them for any significant period of time. For that reason, I feel this is an > important question.
You're right. I have done minimal work with closures, all of it in Perl. Being a long time Java coder, I have to admit that I did approach them as shorthand for single-method anonymous classes even though the language itself did not constrain me to that pattern. Still, I've made use of API and laid out my own that lent themselves very easily to quite effective use of anonymous instances (think Comparator), so I can't say I ever felt like having closures would cause me to write better or substantially more readable code. I understand the issue of flow control, but I can't say I'm seeing very many useful patterns I'd take advantage of that would be different from we can do now. Oh, and BTW, I'm not a particularly big fan of the new for loop either :)
> > In essence here, you've created your own for loop that looks like and acts > > like a language-level control construct. This is what Gafter is referring > > to as "control abstraction".
> > Right. And my point is that if it's possible to "fake" these control > > mechanisms already without performance hits or some other hidden issues, > why > > do we need a change to the language?
> There are a few reasons. For one, not everything that you can do with > closures can be as-easily faked out. Also, this code is not as easy to read > as code written with a custom forEachSuchThat loop construct. The intention > of the code is obscured somewhat by boilerplate. The boilerplate in this > example is small, but it is still there (iter.hasNext(), iter.next(), etc.) > Other examples have much more boilerplate, much of which can be done away > with using closures.
If I need to be able to daisy-chain my conditional subrange statements without forcing evaluation of the range to its end if the outermost control loop terminates early, how would I be able to substantially reduce boilerplate code here even with use of closures?
The concept of Closures having a name and being the talk of the python/ ruby/haskell/lisp fanboys is certainly no reason to include them in the JRE!
Closures allow you to solve certain problems in an elegant and/or maintainable fashion and the abilities to solve those problems are the reason to include them in the next release of java.
I claim that CICE closures allow you to solve 95% of all use cases that would make a functional programmer go: I know! I'll use a closure!
And THAT is the reason why CICE is so much better than gafter. If Gafter claims CICE (read: anonymous classes, CICE is just syntactic sugar for them) aren't true closures, I understand and even agree. However, there are so many things you can do with closures that you can do equally well with anon classes, and anon classes are 'the java way'. In a big way, let me explain:
java.util.Comparator<Integer>, in BGGA land, would become:
int(int, int)
however, this is worthless type info. Of the caliber where python and ruby enthusiasts correctly claim the hassle of the logistics are not worth the benefits of avoiding ClassCastExceptions, because those never happen. The point of static typing is to give a concept a full (namespaced) name, and a place for javadocs, so that you can have those pop up and refer to them right from inside the code at any time.
int(int, int)? What the heck is that? It doesn't even look like Comparator. As far as I know, that seems to be the type of a function that can be assigned to a calculator application's operator buttons (+, -, *, / and the like).
In CICE you would write:
Comparator(int a, int b) { return Math.abs(a) - Math.abs(b); } // Comparator is a single-abstract-method interface or abstract class, so we can use CICE. Return type, throws clause, and any annotations are taken from Comparator's declaration (e.g. the compiler knows compare() returns an int, so this pseudomethod also will)...
and yet this thing is fully typed. It's a COMPARATOR, that sounds logical (in fact, It's a Comparator<Integer>) and I have a place to refer to javadocs for it.
That's the java way. You may not think this way is always appropriate, but that's what JRuby and Groovy are for.
Allowing BGGA closures into java turns java into a balls-less ruby. No thanks. I actually like static typing. A language can't be everything to everybody (people have tried with e.g. PL/I. Ever see any PL/I- based projects around anymore these days?) so java took it to the next step and created a JVM that could be everything to everybody. So far that theory is either working or has yet to prove itself, depending on who you speak to, though the popularity of groovy seems to indicate that its working.
On Mar 21, 3:48 pm, "J. McConnell" <jdo...@gmail.com> wrote:
> On 3/21/07, reinierz <reini...@gmail.com> wrote:
> > You can have your cake (consider anonymous classes java's closures) > > and eat it too (reduce verbiage and make that "final" stuff easier to > > handle):
> > CICE is an alternative closure proposal that is just some light > > syntactic sugaring over what's already there. I think this is the > > single greatest improvement to the java language that can possibly be > > made:
> I'm familiar with CICE and I would be happy to have CICE over nothing, but > the fact is that anonymous inner classes are not closures for the reasons > Gafter puts forward, so CICE doesn't give Java closures. Although I would > find CICE useful, I think it would be a mistake to go half-way with closures > support. If you are going to pull in much of the syntax anyway for CICE, > why not bring in the other supporting functionality that BGGA requires like > function types and a null type?
> The arguments I've heard so far pretty much boil down to the fact that it > just complicates the language too much. Complicates it for who? It might > complicate it some for API writers, but don't you want them to be pretty > capable anyway? Shouldn't API writers be familiar enough with a language to > take advantage of all the tools it provides? The clients of such an API > written to support closures wouldn't need to know any more than they would > to take advantage of CICE in the vast majority of cases.
> Contrast this complication with the Java Security Model. Now, my > understanding is that that thing is a mess (I'm sure necessarily so) that I > wouldn't even take the time to understand unless I had a specific reason to > do so. That doesn't keep me from understanding Java at all, though. Nor > does it keep me from benefiting from some of the safety nets put in place by > the JSM. I think closures, as proposed in BGGA, are similarly complicated > for a few but simple for many.
> java.util.Comparator<Integer>, in BGGA land, would become:
> int(int, int)
> int(int, int)? What the heck is that? It doesn't even look like > Comparator. As far as I know, that seems to be the type of a function > that can be assigned to a calculator application's operator buttons > (+, -, *, / and the like).
> In CICE you would write:
> Comparator(int a, int b) { return Math.abs(a) - Math.abs(b); }
This isn't a fair comparison. While BGGA does have function types, so {int, int => int} is in fact a type, BGGA also allows for something like:
Comparator c = { int a, int b => Math.abs(a) - Math.abs(b); };
As with CICE, single method abstract classes or interfaces can be instantiated with this kind of short-hand.
On 3/22/07, Alexey Zinger <inline_f...@yahoo.com> wrote:
> You're right. I have done minimal work with closures, all of it in Perl.
Present discussion aside, I really would recommend finding some time to work with a language that supports them well. Ruby or lisp would both be good choices. Regardless of whether they end up in Java or not, it will make you a better coder.
Oh, and BTW, I'm not a particularly big fan of the new for loop either :)
> > There are a few reasons. For one, not everything that you can do with > > closures can be as-easily faked out. Also, this code is not as easy to > read > > as code written with a custom forEachSuchThat loop construct. The > intention > > of the code is obscured somewhat by boilerplate. The boilerplate in > this > > example is small, but it is still there (iter.hasNext(), iter.next(), > etc.) > > Other examples have much more boilerplate, much of which can be done > away > > with using closures.
> If I need to be able to daisy-chain my conditional subrange statements > without > forcing evaluation of the range to its end if the outermost control loop > terminates early, how would I be able to substantially reduce boilerplate > code > here even with use of closures?
To be clear, the only boilerplate I was talking about in this example are two lines:
while (iter.hasNext()) { val = iter.next();
Those could be done away with using a closure. Admittedly, that doesn't make much of a difference in this example, but you know you've written a lot of boilerplate in your life in other scenarios ;)
> Comparator c = { int a, int b => Math.abs(a) - Math.abs(b); };
Also unfair.
In this case the Comparator c = prefix makes abundantly clear what's going on here.
However, the type of this:
{ int a, int b => Math.abs(a) - Math.abs(b); };
is (int, int) => int, and NOT comparator!
whereas the CICE equivalent:
Comparator(int a, int b) { return Math.abs(a) - Math.abs(b); };
*IS* specified (Comparator<Integer>) without the need to look up where it's going. This is important, because in the current release of java, it is impossible to carry a half-bound type around that will implicitly become whatever is requested. The closest equivalent is carrying a supertype (or even an Object) around, which gets cast to the 'right' thing at some later point in time. This works, but it's 1) ugly, and 2) everyone tells you not to do this, and there's a good reason. That Isn't Java. That's way more suited to groovy, scala, or jruby. I again repeat: if this is important to you, if your brain prefers to program in this manner, why aren't you using those languages instead?
The reason it's bad IS for refactoring. I know someone in this thread mentioned that adding BGGA closures in fact offers more refactoring opportunities and then showed an example of a standard function-on- collection operation, which does absolutely nothing to prove that point ,which I'm fairly sure is dead wrong. Perhaps we are confusing terminology; refactoring, as in, the compiler (read: whatever you use to write code with, e.g. eclipse, IDEA, or netbeans - assuming we're all working with a notepad with a lot of sugar is unfair, java sucks if you do that, this is known and not something that warrants fixing) can figure out exactly what code fragments you are referring to given a refactoring op. If I want to rewrite all 'comparators' then the refactoring will not be complete as in some code fragments, we have an (int, int) => int that is secretly a comparator. Refactoring is a borderline use-case, but reconsider this same line of reasoning but this time simply with: Find me all places where I have comparators in the first place.
The crucial thing here is: In the current situation, an object intended as a Comparator (or any other type) STARTS as that type (The operation of constructing an object is virtually always typed; constructors are forced, and factories that just return Object are horribly designed) and also ENDS at that type (e.g. you can't toss an Object into Collections.sort(a, (comparator)) and have it silently cast to Comparator; you must be explicit about such things). In CICE land, as the language doesn't change in any way or form (it's just sugar) this is no different, but in BGGA land it is; they end as an implicitly casted Comparator, and start life as an (int, int) => which is only half a type;
it's the syntactic notion of type (e.g. an implicit BGGA cast from (int, int) => to Comparator cannot throw a ClassCastException because syntactically, this 'fits', guaranteed), but it's missing the semantic notion of type: While a Comparator<Integer> and a CalculatorButtonOperation are ENTIRELY DIFFERENT CONCEPTS, as different as night and day, really, by pure coincidence they share the same syntatic function type: (int, int) => int for the both of them. The fact that this can create bugs is only a minor issue, just like the fact that static typing moves 'class cast exceptions' from runtime to write/compile time is only a minor issue: The real point is that while programming you see a lot of types while using other people's (or API's) code, and types serve as implicit, checked, 'documentation'. (int, int) => int is in many situations not a lot of help when sussing out what something does, and there is no opportunity for javadocs.
CalculatorButtonOperation does, as does Comparator. Thus, I declare that any creation of a functor (CICE/java5: An anonymous class, BGGA: a closure), unless it's a massive amount of effort, having an explicitly named fully namespaced type is always better; the shortcut of not supplying one is not for java; that's the strength (and weakness) of other languages. Introducing this to java is making java into a wimpy version of ruby or python. I'd rather have .... ruby or python! - and with JRuby around and the recent resurgence in jython, there is absolutely no reason to move java into that direction.
Unfortunately right now it IS a lot of effort, which is where CICE comes in: Syntactic sugar to reduce the effort. In fact, my code is littered with stuff like this:
Runnable hook = new Runnable() { public void execute() {\n doSomething();\n
}};
where '\n' means: newline in my code. It's a syntax hack to represent that there's really only one conceptual 'level' of indentation going on here, not two. CICE addresses exactly that, and nothing more. Java really owes trying this concept at the very least before unleashing the havoc of BGGA, just to see if this will cover enough ground. I'm in fact sure it will, but I can imagine opinions differ.
As a final note, consider that with CICE closures, most 'function-over- collection' operations become elegant and simple as well, with the right API support. I present you the CICE-ified operations right here: http://www.zwitserloot.com/2006/11/25/closures-yes-java-has-them/
Includes select, python do/with, and others. Note how in all circumstances some light API modifications and CICE makes them look good and act elegant.