After the storm from blog to mailing list, roadmap of New groovy appeared. To some extent, this is a response to groovy is dead, which has been so popular recently. On the other hand, Mike spille, groovy's neighborhood, responded to the criticism of the New groovy feature in the form of a wiki document.
This is the most controversial of all new features, of course: return/break/continue to behave inside closures like these statements work in other blocks (such as the block on a () or while () loop.
In short, this is the unified block and closure.
Here, I can't help it. In fact, I already have an intuitive taste. I re Mike spille on groovy-Dev in January 16:
I think we shoshould regardfoo() {}
As syntax-sugar, this feature eliminate the difference between built-in Flow Structure and user-defined method call.
If = { condition, doSth | if (condition) doSth() }t = { println 'Hello!' }if (true) { println 'Hello!' } // built-in ifIf (true) { println 'Hello!' } // user-defined If is similar tobuilt-in if, that's groovy!If(true, t) // normal method callIf(true, { println 'Hello!' }) // normal method call even the lastparam is a anonymous closure>> The puzzling errors bit is also why I favor a keyword for closures. It'll> not only greatly simplify the grammar and parser, but I think it's better> for users too. It clearly signals where closures are in your code, and> avoids the problems of _users_ not knowing when they have a closure and> when they have a block.
I think there is no essential difference between closure and block. User Have a block, then want to reuse the block. Make the block can be passed or returned or parameterized --- that is closure.
Now it seems that I was close to getting rid of the idea that closure was originally regarded as the anonymous function equivalent in Javascript. I have realized the subtle relationship between closure and general blocks.
Closure syntax largely eliminates the difference between built-in process structures and user-defined methods. In other words, we can easily write a method that accepts the closure parameter, so that its call syntax can be very similar to the syntax structure of while, when (without the else if! Although we still cannot copy special Syntax structures such as for (;) and if-else, this is already a big shock.
Furthermore, I found that block and closure do not exist from the perspective of application programmers.NatureDifference. Block can be seen as a code segment, while closure isReusableCode segment that can be passed, returned, and parameterized.
However, closure conflicts with traditional flow control, which mainly shows how to implement break and continue semantics. Previously, it was recommended that closure return a specific constant tag such as closure. break, and then the caller of closure is responsible for processing the flag.
The bigger problem is that closure conflicts with function (method) as the unit of code function abstraction and reuse. This is the fatal return problem!
Obviously, according to the general idea, closure is a function or method at the underlying layer. The simple structure of the block {Param | expression} is essentially the same as that of block. And from the very beginning till now, this sugar mainly aims to achieve the simplicity of the exquisite gpath. On the other hand, closure should be equal to function in the opinion of JavaScript or people who have a little knowledge about functional programming (FP.
It should be said that the same was true for groovy's closure at the beginning. The only difference is that, for the sake of gpath conciseness, the return design can be omitted (directly return the value of the last statement ).
From then on, almost all closure in groovy codebase has no return keyword. Because it is almost unnecessary, there seems to be no reason to remember it or even mention it. Thus, a door opened ......
Consider a traditional program. This function checks each row of the file and returns the row number of the first row that meets the filter condition. Otherwise,-1 is returned.
def findLine(file, filter) { lineNo = 0f = new File(file)while(!f.isEOF()) {line = f.readLine()if (filter(line)) return lineNo;else ++lineNo} return -1}
Now a newbie has just read several closure examples, so I'm excited, so I used closure style to write:
def findLine(file, filter) { lineNo = 0 new File(file).eachLine { line | if (filter(line)) return lineNo; else ++lineNo } return -1}
Okay, everything looks right. The Code clearly expresses the main idea of the program, and there is almost nothing redundant.
However, unfortunately, this program cannot achieve the expected results in classic groovy, and findline always returns-1!
Because the return in the anonymous closure after eachline is returned from the closure to the call point inside the eachline method (in fact, the eachline method simply ignores the return value, and no one is expecting it ), instead of returning the code as expected to the findline caller!
Okay, this is a programmer's problem. Misuse of return -- some people will make a simple conclusion. How to use the recommended closure. the break constant sign is used to achieve this function. No matter how intuitive this return is, groovy's goal is to enable programmers to work intuitively (removing the annoying program Terminator; in fact, cross-row is allowed, as an example), the problem cannot be simply blamed on programmers.
As mentioned above, in this structure, the intention of return is very clear. Without prejudice, almost any Java programmer will write such a program after turning to groovy. Since closure is widely used to simplify iteration structures (Martin flower claims that he misses closure in languages without closure), for programmers who have switched from C-style, in the face of the most commonly used each, it is natural to regard it as a substitute for the for and while structures, so it is natural to regard return as returning from findline, rather than returning from anonymous closure.
In this regard, Mike spille's opinion is: Everything is caused by closure being too block. Programmers forget that this is actually a syntax sugar, which is essentially a method rather than a block, this leads to a programmer error expecting the return location of the return. In this case, we should clarify where block is and where closure is. It is recommended to add a keyword indicating closure, such as def {closure code ...}
Someone pointed out that it is better to use C # Delegate! (On the other hand, it is also the actual situation of JS. The function keyword is equivalent to this keyword)
In either case, the situation is clear: the common block and closure are so similar in syntax that they cannot be distinguished. The solution is nothing more than separating them (Mike spille's advice ), or unify them -- make the semantics of break/return consistent in block and closure!
The solution proposed by John rose and accepted by most people is to make closure's return act as the programmer most likely expects: Return to the function that defines it. He also referred to Smalltalk, Ruby, and LISP to propose break and continue to improve syntax and semantics in closure. Therefore, we can use the syntax structure of continue l: Value in closure to return value from label L. (Of course, there are very few opportunities to use such a weird continue. In my consistent tone, you can use XXX, but if you need XXX, it is often a signal of bad taste ......)
For this proposal, Mike spille naturally opposed it and the criticism also involved issues such as the development progress and management mode. If I'm not mistaken, Mike spille's rant (although he doesn't admit it himself) even repeatedly asked several core figures to step down ...... : D
By the way, I was not aware of this problem when I wrote the previous mail. John Wilson's Re pointed out this tricky problem to me:
On 16 Jan 2005, at 13:53, Shijun He wrote:> I think there is no essential difference between closure and block.> User have a block, then want to reuse the block. make the block can be> passed or returned or parameterized --- that is closure.>this is almost true but not quite..if (a == 1) { return // returns from enclosing function}a.each { return // returns from closure}this (and break in a closure) catches people out a lot.This has been discussed a great deal but we have not come up with asolution which pleases everybody.
Apparently, pleases everybody is mission impossible. In fact, it's a huge noise ...... Mike spille has been named fud.
In recent days, I have also discussed this issue with Comrade PT, and pulled out Ruby and lisp/scheme to "root ". Comrade PT's opinion is surprisingly consistent with that of Mike spille. PT insisted that closure should be a function, and changing the semantics of return is unacceptable. But ruby's current situation is closer to what John Rose said (at least the return of anonymous closure does not return closure itself and returns to upper-layer functions ). If we do not doubt John Rose's professional skills (this is something Mike spille admitted, John is a master with multi-language experience), then closure's return semantics, it is the language standard of smalltalk, while Ruby has a lot of concepts that are based on smalltalk, and closure should be no exception. Furthermore, James Strachan, the main designer of groovy, spoke: We don't want to change anything, but to clarify the semantics of the return/break/continue that has never been clearly defined, it is necessary to completely implement the functionality of closure that has not yet been fully implemented. (I want to say something like this: I am confused about it :)).
The problem finally entered the "Philosophy" stage (please do not misunderstand that I am teasing philosophy ). That is, "What is closure ". Obviously, so far I have been more confident in John Rose's statement. This is the case for closure since lisp, that is, a special block structure. Even many of Mike spille's arguments only mean that groovy's goal is to be a Java programmer, so it is not necessary to fully "turn to the West". We should first consider the degree of acceptance of Java programmers, for example, the unification of closure/block will undermine the knowledge base of the Java program structure. (However, after I read the story 'Closure in Java ', I cannot convince myself .)
Common LISP, with special operators called block, and return-from, can return to any specified level! It is a super thorough block !! On the other hand, PT strongly believes that closure is lambda, or Lambda in imperative language (OO language ?) . He also believes that the jump to the upper-level Lex should be implemented in call/CC mode. I know very little about lisp/scheme, and it is impossible to think clearly about this subtask. But at least one thing is clear: groovy's choice has been made, and I think this is in line with its core value. As for its relationship with block, func, and method, I have no idea yet. Let's move on first ......