Re: About eliminating ambiguities of method call with closure argument
I see, then I agree that it's not a big issue. I was confused because I saw that Gradle supports that syntax. Not understanding how they can, then? Cheers, p On Wed, Apr 1, 2020 at 3:30 PM Paul King wrote: > Groovy 2.5 and earlier don't support this form. But yes, if any Groovy 3 > DSLs were created in the last few weeks (or longer if we count betas/RCs) > and they used this form, then they would break. > > Cheers, Paul. > > On Wed, Apr 1, 2020 at 10:56 PM Paolo Di Tommaso < > paolo.ditomm...@gmail.com> wrote: > >> Arriving late to this thread, therefore not sure it has already >> discussed, but have you taken in consideration that changing the method >> call argument interpretation for the case 1, eg. >> >> meth >> { p -> >> } >> >> it will break all DSL in which the user scripts use this form? Just >> thinking Gradle for example. >> >> >> Cheers, >> Paolo >> >> >> On Mon, Mar 30, 2020 at 3:06 PM MG wrote: >> >>> I see, that's a though one, then, if one wants people to be able to put >>> heir braces where they want*... >>> >>> I have turned this back and forth in my mind, and I think the current >>> Groovy 2.5.x behavior is actually a good/practical compromise, even though >>> it might appear confusing at first in some cases. >>> >>> Rationale: >>> >>> *Alternative case 1: Having a the closure on a new line always being >>> separate from the previous line* >>> >>> This would prohibit Groovy code where a closure is used like a block >>> construct (a very powerful Groovy pattern imho) to be written as (e.g.): >>> >>> void myDatabaseProcessingMethod() { >>> // The closure following the next line will be passed as parameter >>> to the forEachResultSetRow method >>> sqe.forEachResultSetRow("select * from PERSON") >>> { >>> // many lines of result row processing >>> } >>> >>> // Note: Forcing people to write this with a line-continuation >>> character to me would make no sense, e.g.: >>> sqe.forEachResultSetRow("select * from PERSON") \ >>> { >>> // many lines of result row processing >>> } >>> } >>> >>> forcing people to put opening brackets on the same line as the >>> forEachResultSetRow call, thereby potentially breaking their coding style. >>> >>> *Alternative case 2: Having a the closure on a new line always being >>> bound to the previous line* >>> >>> This would force Spock (and maybe other DSL) users to use a semicolon at >>> the end of line 1 in your example, which is a breaking change. It also >>> could lead to silently failing code. >>> >>> >>> *Conclusion* >>> >>> So I would keep the Groovy 2.5.x behavior, but if I absolutely had to >>> choose one of the above options, I would go with the opposite of what you >>> propose, and always bind the closure to the previous line, since otherwise >>> there would be no acceptable way for the closure-as-block-construct pattern >>> to be able to support having the block construct start on its own line (I >>> don't see putting in a line continuation character as a viable solution >>> here), whereas for DSLs putting in a semicolon in these cases would imho be >>> OK (legacy breaking changes/silently failing code put aside). >>> >>> (The only other ideas I have is to support making the parsing behavior >>> switchable, enabling one of the above behaviors through e.g. an >>> "@ParseSpock" annotation (with always binding to the previous line being >>> the default behavior), or by allowing a DSL/library developer to qualify >>> whether a closure parameter can be bound from the next line or not; but 1) >>> I have no idea if that is even technically feasible, and 2) I doubt we >>> would want to go down that route.) >>> >>> Cheers, >>> mg >>> >>> *Note: I have put opening braces on the same line since programming C in >>> the 80s, so personally have no problem with this :-) >>> >>> >>> >>> On 29/03/2020 04:25, Daniel.Sun wrote: >>> >>> Hi MG, >>> >>> Understood. Some spock code care the differences, e.g. the following >>> code >>> ``` >>> modification| expected >>> { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) >>> ``` >>> >>> is expected to parsed as 2 binary expressions: >>> >>> ``` >>> modification| expected >>> ``` >>> and >>> ``` >>> { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) >>> ``` >>> >>> >>> Cheers, >>> Daniel.Sun >>> >>> >>> >>> - >>> Apache Groovy committer & PMC member >>> Blog: http://blog.sunlan.me >>> Twitter: @daniel_sun >>> >>> -- >>> Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html >>> >>> >>>
Re: About eliminating ambiguities of method call with closure argument
Groovy 2.5 and earlier don't support this form. But yes, if any Groovy 3 DSLs were created in the last few weeks (or longer if we count betas/RCs) and they used this form, then they would break. Cheers, Paul. On Wed, Apr 1, 2020 at 10:56 PM Paolo Di Tommaso wrote: > Arriving late to this thread, therefore not sure it has already discussed, > but have you taken in consideration that changing the method call argument > interpretation for the case 1, eg. > > meth > { p -> > } > > it will break all DSL in which the user scripts use this form? Just > thinking Gradle for example. > > > Cheers, > Paolo > > > On Mon, Mar 30, 2020 at 3:06 PM MG wrote: > >> I see, that's a though one, then, if one wants people to be able to put >> heir braces where they want*... >> >> I have turned this back and forth in my mind, and I think the current >> Groovy 2.5.x behavior is actually a good/practical compromise, even though >> it might appear confusing at first in some cases. >> >> Rationale: >> >> *Alternative case 1: Having a the closure on a new line always being >> separate from the previous line* >> >> This would prohibit Groovy code where a closure is used like a block >> construct (a very powerful Groovy pattern imho) to be written as (e.g.): >> >> void myDatabaseProcessingMethod() { >> // The closure following the next line will be passed as parameter >> to the forEachResultSetRow method >> sqe.forEachResultSetRow("select * from PERSON") >> { >> // many lines of result row processing >> } >> >> // Note: Forcing people to write this with a line-continuation >> character to me would make no sense, e.g.: >> sqe.forEachResultSetRow("select * from PERSON") \ >> { >> // many lines of result row processing >> } >> } >> >> forcing people to put opening brackets on the same line as the >> forEachResultSetRow call, thereby potentially breaking their coding style. >> >> *Alternative case 2: Having a the closure on a new line always being >> bound to the previous line* >> >> This would force Spock (and maybe other DSL) users to use a semicolon at >> the end of line 1 in your example, which is a breaking change. It also >> could lead to silently failing code. >> >> >> *Conclusion* >> >> So I would keep the Groovy 2.5.x behavior, but if I absolutely had to >> choose one of the above options, I would go with the opposite of what you >> propose, and always bind the closure to the previous line, since otherwise >> there would be no acceptable way for the closure-as-block-construct pattern >> to be able to support having the block construct start on its own line (I >> don't see putting in a line continuation character as a viable solution >> here), whereas for DSLs putting in a semicolon in these cases would imho be >> OK (legacy breaking changes/silently failing code put aside). >> >> (The only other ideas I have is to support making the parsing behavior >> switchable, enabling one of the above behaviors through e.g. an >> "@ParseSpock" annotation (with always binding to the previous line being >> the default behavior), or by allowing a DSL/library developer to qualify >> whether a closure parameter can be bound from the next line or not; but 1) >> I have no idea if that is even technically feasible, and 2) I doubt we >> would want to go down that route.) >> >> Cheers, >> mg >> >> *Note: I have put opening braces on the same line since programming C in >> the 80s, so personally have no problem with this :-) >> >> >> >> On 29/03/2020 04:25, Daniel.Sun wrote: >> >> Hi MG, >> >> Understood. Some spock code care the differences, e.g. the following >> code >> ``` >> modification| expected >> { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) >> ``` >> >> is expected to parsed as 2 binary expressions: >> >> ``` >> modification| expected >> ``` >> and >> ``` >> { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) >> ``` >> >> >> Cheers, >> Daniel.Sun >> >> >> >> - >> Apache Groovy committer & PMC member >> Blog: http://blog.sunlan.me >> Twitter: @daniel_sun >> >> -- >> Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html >> >> >>
Re: About eliminating ambiguities of method call with closure argument
Arriving late to this thread, therefore not sure it has already discussed, but have you taken in consideration that changing the method call argument interpretation for the case 1, eg. meth { p -> } it will break all DSL in which the user scripts use this form? Just thinking Gradle for example. Cheers, Paolo On Mon, Mar 30, 2020 at 3:06 PM MG wrote: > I see, that's a though one, then, if one wants people to be able to put > heir braces where they want*... > > I have turned this back and forth in my mind, and I think the current > Groovy 2.5.x behavior is actually a good/practical compromise, even though > it might appear confusing at first in some cases. > > Rationale: > > *Alternative case 1: Having a the closure on a new line always being > separate from the previous line* > > This would prohibit Groovy code where a closure is used like a block > construct (a very powerful Groovy pattern imho) to be written as (e.g.): > > void myDatabaseProcessingMethod() { > // The closure following the next line will be passed as parameter to > the forEachResultSetRow method > sqe.forEachResultSetRow("select * from PERSON") > { > // many lines of result row processing > } > > // Note: Forcing people to write this with a line-continuation > character to me would make no sense, e.g.: > sqe.forEachResultSetRow("select * from PERSON") \ > { > // many lines of result row processing > } > } > > forcing people to put opening brackets on the same line as the > forEachResultSetRow call, thereby potentially breaking their coding style. > > *Alternative case 2: Having a the closure on a new line always being bound > to the previous line* > > This would force Spock (and maybe other DSL) users to use a semicolon at > the end of line 1 in your example, which is a breaking change. It also > could lead to silently failing code. > > > *Conclusion* > > So I would keep the Groovy 2.5.x behavior, but if I absolutely had to > choose one of the above options, I would go with the opposite of what you > propose, and always bind the closure to the previous line, since otherwise > there would be no acceptable way for the closure-as-block-construct pattern > to be able to support having the block construct start on its own line (I > don't see putting in a line continuation character as a viable solution > here), whereas for DSLs putting in a semicolon in these cases would imho be > OK (legacy breaking changes/silently failing code put aside). > > (The only other ideas I have is to support making the parsing behavior > switchable, enabling one of the above behaviors through e.g. an > "@ParseSpock" annotation (with always binding to the previous line being > the default behavior), or by allowing a DSL/library developer to qualify > whether a closure parameter can be bound from the next line or not; but 1) > I have no idea if that is even technically feasible, and 2) I doubt we > would want to go down that route.) > > Cheers, > mg > > *Note: I have put opening braces on the same line since programming C in > the 80s, so personally have no problem with this :-) > > > > On 29/03/2020 04:25, Daniel.Sun wrote: > > Hi MG, > > Understood. Some spock code care the differences, e.g. the following > code > ``` > modification| expected > { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) > ``` > > is expected to parsed as 2 binary expressions: > > ``` > modification| expected > ``` > and > ``` > { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) > ``` > > > Cheers, > Daniel.Sun > > > > - > Apache Groovy committer & PMC member > Blog: http://blog.sunlan.me > Twitter: @daniel_sun > > -- > Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html > > >
Re: About eliminating ambiguities of method call with closure argument
I see, that's a though one, then, if one wants people to be able to put heir braces where they want*... I have turned this back and forth in my mind, and I think the current Groovy 2.5.x behavior is actually a good/practical compromise, even though it might appear confusing at first in some cases. Rationale: *Alternative case 1: Having a the closure on a new line always being separate from the previous line* This would prohibit Groovy code where a closure is used like a block construct (a very powerful Groovy pattern imho) to be written as (e.g.): void myDatabaseProcessingMethod() { // The closure following the next line will be passed as parameter to the forEachResultSetRow method sqe.forEachResultSetRow("select * from PERSON") { // many lines of result row processing } // Note: Forcing people to write this with a line-continuation character to me would make no sense, e.g.: sqe.forEachResultSetRow("select * from PERSON") \ { // many lines of result row processing } } forcing people to put opening brackets on the same line as the forEachResultSetRow call, thereby potentially breaking their coding style. *Alternative case 2: Having a the closure on a new line always being bound to the previous line* This would force Spock (and maybe other DSL) users to use a semicolon at the end of line 1 in your example, which is a breaking change. It also could lead to silently failing code. *Conclusion* So I would keep the Groovy 2.5.x behavior, but if I absolutely had to choose one of the above options, I would go with the opposite of what you propose, and always bind the closure to the previous line, since otherwise there would be no acceptable way for the closure-as-block-construct pattern to be able to support having the block construct start on its own line (I don't see putting in a line continuation character as a viable solution here), whereas for DSLs putting in a semicolon in these cases would imho be OK (legacy breaking changes/silently failing code put aside). (The only other ideas I have is to support making the parsing behavior switchable, enabling one of the above behaviors through e.g. an "@ParseSpock" annotation (with always binding to the previous line being the default behavior), or by allowing a DSL/library developer to qualify whether a closure parameter can be bound from the next line or not; but 1) I have no idea if that is even technically feasible, and 2) I doubt we would want to go down that route.) Cheers, mg *Note: I have put opening braces on the same line since programming C in the 80s, so personally have no problem with this :-) On 29/03/2020 04:25, Daniel.Sun wrote: Hi MG, Understood. Some spock code care the differences, e.g. the following code ``` modification| expected { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) ``` is expected to parsed as 2 binary expressions: ``` modification| expected ``` and ``` { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) ``` Cheers, Daniel.Sun - Apache Groovy committer & PMC member Blog: http://blog.sunlan.me Twitter: @daniel_sun -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Re: About eliminating ambiguities of method call with closure argument
On 29.03.20 14:17, Paul King wrote: Groovy's original rule was that a newline terminates a statement when it could sensibly finish (successfully complete an expression) at that point. So if you've opened a curly brace or bracket, for instance, the newline would not auto-terminate an expression/statement. The rule was later expanded with some lookahead to also merge lines when the subsequent line couldn't be a valid statement in its own right. This allows the following for example in Groovy 3: def truth = maybe && possibly For me the whole problem here is actually Java. People did always write things similar to this: """ memberNames.stream().filter((s) -> s.startsWith("A")) .map(String::toUpperCase) .forEach(System.out::println); """ and IDEs like Intellij IDEA are actually forcing you into this style quite a bit. The dot is not our problem though, it is the curly brace, plus and minus in combination with optional return. """ def x = "some long text" + "another line" """ As we all know for Groovy this can mean two expression statements or one while in """ def x = "some long text" + "another line" """ it is very clear for the compiler that the lines belong together. So if we make the first PLUS - example two statements we essentially "broke" Java code. So I was thinking we could do something intelligent with the compiler and react differently if we have the last line or not... only that will not solve the Spock problem at all. So I have another alternative to suggest (besides ditching trying to be so exact source compatible with Java), and that is: * make plus and minus always align to the line before, essentially disabling standalone unary plus and minus. If you want to return them, you will have to write return. * make Closure and block on the next line always detached from the line before. If they are supposed to belong together, then the curly brace has to be on the line before. Coming back to the examples before: ``` meth { p -> } ``` and ``` a | meth { p -> } ``` will be two expression statements, while ``` meth { p -> } ``` will be one. And yes, I fully expect this to break existing code. And yes, that is basically an inconsistent rule, since we handle +/- different from {... though there is a difference between a syntax element like { and a binary/unary operator bye Jochen
Re: About eliminating ambiguities of method call with closure argument
Groovy's original rule was that a newline terminates a statement when it could sensibly finish (successfully complete an expression) at that point. So if you've opened a curly brace or bracket, for instance, the newline would not auto-terminate an expression/statement. The rule was later expanded with some lookahead to also merge lines when the subsequent line couldn't be a valid statement in its own right. This allows the following for example in Groovy 3: def truth = maybe && possibly The string concatenation example doesn't work because of the unaryPlus/unaryMinus operators. I'd be keen to do a GEP to see those removed (obviously retained for numbers but no longer overridable) for Groovy 4, then we could also support the String concatenation example and a bunch of edge cases we currently can't support could be handled (e.g. we currently support "def x = -0.4" but not "def y = -.4"). But that is a separate issue in any case. The issue at hand for GROOVY-9484 is whether we can simplify our grammar rules and the exceptional cases that users need to remember. There are several paths which lead to simpler rules than we have now. Some of those would impact existing Spock code. If we put our thinking caps on we might even be able to find alternative (even better?) solutions for Spock. It would certainly also be good to capture the whitespace rules more clearly in our documentation. Paul. On Sun, Mar 29, 2020 at 11:03 AM Remko Popma wrote: > > > On Mar 29, 2020, at 0:19, Milles, Eric (TR Tech, Content & Ops) < > eric.mil...@thomsonreuters.com> wrote: > > > > Is there any language that differentiates between one space and > multiple whitespaces as a separator? My experience with C, C++, Java, > Groovy, etc. is that any number of whitespaces are the same in terms of > separation between tokens. > Not really: > > String accepted = "a" + > "b" // works, gives "ab" > > String bad = "a" > + "b" // compile error > > So, white space is significant in Groovy. > > > > > In terms of parsing, you can't tell that an identifier is a method name > -- you mention below closure follows method name -- you don't know until > semantic analysis and possibly runtime in terms of dynamic Groovy if an > identifier refers to a method name. > > > > > > Can the user insert a semicolon to disambiguate? > > ``` > > a | meth ; // now the parser knows this statement is over > > { p -> > > } > > ``` > > > > I don't think you are ever going to see an end to ambiguous constructs > due to optional parentheses and semicolons. > > > > -Original Message- > > From: Daniel.Sun > > Sent: Friday, March 27, 2020 10:06 PM > > To: d...@groovy.incubator.apache.org > > Subject: About eliminating ambiguities of method call with closure > argument > > > > Hi all, > > > > Current groovy grammar of method call contains the following > ambiguities, which are odd for users. For example, > > > > 1) method call with closure argument. That means the closure on the next > line could be treated as argument of method `meth` ``` meth { p -> } ``` > > > > 2) binary expression and closure expression. That means the closure is > not an argument. > > ``` > > a | meth > > { p -> > > } > > ``` > > > > I propose to unify the grammar of closure arguments: when closure > follows method name directly, it is an argument, otherwise it is just > standalone closure. For example, > > > > 3) method call with closure argument > > ``` > > meth { p -> > > } > > ``` > > > > 4) variable and closure > > ``` > > meth > > { p -> > > } > > ``` > > > > Luckily, groovy-parser project containing source code of some > famous groovy projects, none of which are broken because of the proposed > change[1]. > > > > Here is a JIRA ticket[2] to track the proposed change, and here is > the PR[3] to implement the change. > > > > Any thoughts? > > > > Cheers, > > Daniel Sun > > [1] > https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdanielsun1106%2Fgroovy-parser%2Fcommits%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=qdhNufAqJP8kpOtsz1QWwz2b06pR%2F1v5loQnNcuWWRM%3Dreserved=0 > > [2] > https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fissues.apache.org%2Fjira%2Fbrowse%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=Z3FyviGcsG4EtvIGiAv889dG%2F2p%2FhqClAED998%2BnT98%3Dreserved=0 > > [3] > https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fapache%2Fgroovy%2Fpull%2F1211data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=iXdv8OT3BMIyno8R3TlLclEB1%2BSd%2BxPlCaxhacydSqA%3Dreserved=0 > > > > > > > > > > - > > Apache Groovy committer & PMC
Re: About eliminating ambiguities of method call with closure argument
Nice catch ;-) Cheers, Daniel.Sun - Apache Groovy committer & PMC member Blog: http://blog.sunlan.me Twitter: @daniel_sun -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Re: About eliminating ambiguities of method call with closure argument
Hi Jochen, > How about unifying the other way around and make 1 and 2 both a method > call with a closure for meth? Groovy 3 has already unified them by accident... but some spock code is broken, so we are trying to find a way to please everyone ;-) ``` modification| expected { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) ``` (See https://issues.apache.org/jira/browse/GROOVY-9484) Cheers, Daniel Sun - Apache Groovy committer & PMC member Blog: http://blog.sunlan.me Twitter: @daniel_sun -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Re: About eliminating ambiguities of method call with closure argument
Hi MG, Understood. Some spock code care the differences, e.g. the following code ``` modification| expected { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) ``` is expected to parsed as 2 binary expressions: ``` modification| expected ``` and ``` { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) ``` Cheers, Daniel.Sun - Apache Groovy committer & PMC member Blog: http://blog.sunlan.me Twitter: @daniel_sun -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
RE: About eliminating ambiguities of method call with closure argument
Actually, we have already force some code style... But the code style is not unified: 2.5.8 parses the following code as a variable and a method call with closure argument ``` a | meth { p -> } ``` Let's add a newline. 2.5.8 parses the following code as binary expression and a closure ``` a | meth { p -> } ``` But 3.0.2 parses the above both code as a variable and a method call with closure argument. To be frank, I am inclined to accept the behaviour of 3.0.2, it is unified, but it breaks some spock code: ``` modification| expected { Instant i, ZoneId z -> i.plusSeconds(1) } | defaultInstant.plusSeconds(1) ``` (See https://issues.apache.org/jira/browse/GROOVY-9484) Cheers, Daniel.Sun - Apache Groovy committer & PMC member Blog: http://blog.sunlan.me Twitter: @daniel_sun -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
RE: About eliminating ambiguities of method call with closure argument
AFAIK, Groovy learned quite a few design ideas from many great language, e.g. Ruby. The optional parentheses feature was inspired by Ruby. The feature makes Groovy more friendly as DSL to users, but ambiguities introduced... Ruby has similar troubles(See the following link) https://stackoverflow.com/questions/26480823/why-does-white-space-affect-ruby-function-calls Cheers, Daniel.Sun - Apache Groovy committer & PMC member Blog: http://blog.sunlan.me Twitter: @daniel_sun -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Re: About eliminating ambiguities of method call with closure argument
> On Mar 29, 2020, at 0:19, Milles, Eric (TR Tech, Content & Ops) > wrote: > > Is there any language that differentiates between one space and multiple > whitespaces as a separator? My experience with C, C++, Java, Groovy, etc. is > that any number of whitespaces are the same in terms of separation between > tokens. Not really: String accepted = "a" + "b" // works, gives "ab" String bad = "a" + "b" // compile error So, white space is significant in Groovy. > > In terms of parsing, you can't tell that an identifier is a method name -- > you mention below closure follows method name -- you don't know until > semantic analysis and possibly runtime in terms of dynamic Groovy if an > identifier refers to a method name. > > > Can the user insert a semicolon to disambiguate? > ``` > a | meth ; // now the parser knows this statement is over > { p -> > } > ``` > > I don't think you are ever going to see an end to ambiguous constructs due to > optional parentheses and semicolons. > > -Original Message- > From: Daniel.Sun > Sent: Friday, March 27, 2020 10:06 PM > To: d...@groovy.incubator.apache.org > Subject: About eliminating ambiguities of method call with closure argument > > Hi all, > > Current groovy grammar of method call contains the following > ambiguities, which are odd for users. For example, > > 1) method call with closure argument. That means the closure on the next line > could be treated as argument of method `meth` ``` meth { p -> } ``` > > 2) binary expression and closure expression. That means the closure is not an > argument. > ``` > a | meth > { p -> > } > ``` > > I propose to unify the grammar of closure arguments: when closure > follows method name directly, it is an argument, otherwise it is just > standalone closure. For example, > > 3) method call with closure argument > ``` > meth { p -> > } > ``` > > 4) variable and closure > ``` > meth > { p -> > } > ``` > > Luckily, groovy-parser project containing source code of some famous > groovy projects, none of which are broken because of the proposed change[1]. > > Here is a JIRA ticket[2] to track the proposed change, and here is the > PR[3] to implement the change. > > Any thoughts? > > Cheers, > Daniel Sun > [1] > https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdanielsun1106%2Fgroovy-parser%2Fcommits%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=qdhNufAqJP8kpOtsz1QWwz2b06pR%2F1v5loQnNcuWWRM%3Dreserved=0 > [2] > https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fissues.apache.org%2Fjira%2Fbrowse%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=Z3FyviGcsG4EtvIGiAv889dG%2F2p%2FhqClAED998%2BnT98%3Dreserved=0 > [3] > https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fapache%2Fgroovy%2Fpull%2F1211data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=iXdv8OT3BMIyno8R3TlLclEB1%2BSd%2BxPlCaxhacydSqA%3Dreserved=0 > > > > > - > Apache Groovy committer & PMC member > Blog: > https://nam02.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.sunlan.medata=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=70Xxc7%2Bg6iF7bhVISTRF48hxQkUb5%2F7iuuofMttDF2o%3Dreserved=0 > Twitter: @daniel_sun > > -- > Sent from: > https://nam02.safelinks.protection.outlook.com/?url=http%3A%2F%2Fgroovy.329449.n5.nabble.com%2FGroovy-Dev-f372993.htmldata=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=bGnd%2BrQj%2FPKljTtkIdT2fFyGF9aQb0QgR1RzQlWRPsY%3Dreserved=0
Re: About eliminating ambiguities of method call with closure argument
On 28.03.20 04:06, Daniel.Sun wrote: Hi all, Current groovy grammar of method call contains the following ambiguities, which are odd for users. For example, 1) method call with closure argument. That means the closure on the next line could be treated as argument of method `meth` ``` meth { p -> } ``` 2) binary expression and closure expression. That means the closure is not an argument. ``` a | meth { p -> } ``` I propose to unify the grammar of closure arguments: when closure follows method name directly, it is an argument, otherwise it is just standalone closure. For example, 3) method call with closure argument ``` meth { p -> } ``` 4) variable and closure ``` meth { p -> } ``` [...] How about unifying the other way around and make 1 and 2 both a method call with a closure for meth? bye Jochen
Re: About eliminating ambiguities of method call with closure argument
Hi Daniel, good to hear you seem to be well :-) Maybe I am missing something, but right now I don't see where writing a standalone closure in the code would makes sense, since it is not assigned to anything, and its creation has no side effects (?) The only application I can see is calling it immediately inline, which I have sometimes done in the past to do e.g. some if-then-else-cascade based calculations depending on parameters/variables from surrounding scope and assign the result to a final variable (without having to introduce a method). I have however switched to using a static eval method for that case, since it is much cleaner: final x = { ... }.call() final x = eval { ... } with statically imported (trivial) eval method static T eval(final Closure cls) { cls() } Cheers, mg On 28/03/2020 04:06, Daniel.Sun wrote: Hi all, Current groovy grammar of method call contains the following ambiguities, which are odd for users. For example, 1) method call with closure argument. That means the closure on the next line could be treated as argument of method `meth` ``` meth { p -> } ``` 2) binary expression and closure expression. That means the closure is not an argument. ``` a | meth { p -> } ``` I propose to unify the grammar of closure arguments: when closure follows method name directly, it is an argument, otherwise it is just standalone closure. For example, 3) method call with closure argument ``` meth { p -> } ``` 4) variable and closure ``` meth { p -> } ``` Luckily, groovy-parser project containing source code of some famous groovy projects, none of which are broken because of the proposed change[1]. Here is a JIRA ticket[2] to track the proposed change, and here is the PR[3] to implement the change. Any thoughts? Cheers, Daniel Sun [1] https://github.com/danielsun1106/groovy-parser/commits/GROOVY-9484 [2] https://issues.apache.org/jira/browse/GROOVY-9484 [3] https://github.com/apache/groovy/pull/1211 - Apache Groovy committer & PMC member Blog: http://blog.sunlan.me Twitter: @daniel_sun -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
RE: About eliminating ambiguities of method call with closure argument
Additionally, you are forcing the hand of users in terms of brace style if you require a closure to have its opening brace on the same line as the method call/name. -Original Message- From: Milles, Eric (TR Tech, Content & Ops) Sent: Saturday, March 28, 2020 10:20 AM To: dev@groovy.apache.org Subject: RE: About eliminating ambiguities of method call with closure argument Is there any language that differentiates between one space and multiple whitespaces as a separator? My experience with C, C++, Java, Groovy, etc. is that any number of whitespaces are the same in terms of separation between tokens. In terms of parsing, you can't tell that an identifier is a method name -- you mention below closure follows method name -- you don't know until semantic analysis and possibly runtime in terms of dynamic Groovy if an identifier refers to a method name. Can the user insert a semicolon to disambiguate? ``` a | meth ; // now the parser knows this statement is over { p -> } ``` I don't think you are ever going to see an end to ambiguous constructs due to optional parentheses and semicolons. -Original Message- From: Daniel.Sun Sent: Friday, March 27, 2020 10:06 PM To: d...@groovy.incubator.apache.org Subject: About eliminating ambiguities of method call with closure argument Hi all, Current groovy grammar of method call contains the following ambiguities, which are odd for users. For example, 1) method call with closure argument. That means the closure on the next line could be treated as argument of method `meth` ``` meth { p -> } ``` 2) binary expression and closure expression. That means the closure is not an argument. ``` a | meth { p -> } ``` I propose to unify the grammar of closure arguments: when closure follows method name directly, it is an argument, otherwise it is just standalone closure. For example, 3) method call with closure argument ``` meth { p -> } ``` 4) variable and closure ``` meth { p -> } ``` Luckily, groovy-parser project containing source code of some famous groovy projects, none of which are broken because of the proposed change[1]. Here is a JIRA ticket[2] to track the proposed change, and here is the PR[3] to implement the change. Any thoughts? Cheers, Daniel Sun [1] https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdanielsun1106%2Fgroovy-parser%2Fcommits%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7C55746422d5ec42d281f508d7d32b7c3a%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637210056033516926sdata=lnEsUtHUU%2FqUXzlEvJA41AkWkXX0g6Ur2o2b5Vye3bM%3Dreserved=0 [2] https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fissues.apache.org%2Fjira%2Fbrowse%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7C55746422d5ec42d281f508d7d32b7c3a%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637210056033526920sdata=fVNF6la9ogHDBgM8uj%2FstRAqnUUXThrlHq%2BEdK7Qq%2BY%3Dreserved=0 [3] https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fapache%2Fgroovy%2Fpull%2F1211data=02%7C01%7Ceric.milles%40thomsonreuters.com%7C55746422d5ec42d281f508d7d32b7c3a%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637210056033526920sdata=alJQcVNgAdYlyLyk%2FpD%2BBMo3dLGKhwqlkV3LTbR%2BxS8%3Dreserved=0 - Apache Groovy committer & PMC member Blog: https://nam02.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.sunlan.medata=02%7C01%7Ceric.milles%40thomsonreuters.com%7C55746422d5ec42d281f508d7d32b7c3a%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637210056033526920sdata=IQu4X3%2BFtC7BAVDSqKqGnAcgkicXXiI8XLH8mqI4g8s%3Dreserved=0 Twitter: @daniel_sun -- Sent from: https://nam02.safelinks.protection.outlook.com/?url=http%3A%2F%2Fgroovy.329449.n5.nabble.com%2FGroovy-Dev-f372993.htmldata=02%7C01%7Ceric.milles%40thomsonreuters.com%7C55746422d5ec42d281f508d7d32b7c3a%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637210056033526920sdata=jEmfYhHiJgpJJePXCtrIl9pChfqfBlWSPv4ebp%2FpliY%3Dreserved=0
RE: About eliminating ambiguities of method call with closure argument
Is there any language that differentiates between one space and multiple whitespaces as a separator? My experience with C, C++, Java, Groovy, etc. is that any number of whitespaces are the same in terms of separation between tokens. In terms of parsing, you can't tell that an identifier is a method name -- you mention below closure follows method name -- you don't know until semantic analysis and possibly runtime in terms of dynamic Groovy if an identifier refers to a method name. Can the user insert a semicolon to disambiguate? ``` a | meth ; // now the parser knows this statement is over { p -> } ``` I don't think you are ever going to see an end to ambiguous constructs due to optional parentheses and semicolons. -Original Message- From: Daniel.Sun Sent: Friday, March 27, 2020 10:06 PM To: d...@groovy.incubator.apache.org Subject: About eliminating ambiguities of method call with closure argument Hi all, Current groovy grammar of method call contains the following ambiguities, which are odd for users. For example, 1) method call with closure argument. That means the closure on the next line could be treated as argument of method `meth` ``` meth { p -> } ``` 2) binary expression and closure expression. That means the closure is not an argument. ``` a | meth { p -> } ``` I propose to unify the grammar of closure arguments: when closure follows method name directly, it is an argument, otherwise it is just standalone closure. For example, 3) method call with closure argument ``` meth { p -> } ``` 4) variable and closure ``` meth { p -> } ``` Luckily, groovy-parser project containing source code of some famous groovy projects, none of which are broken because of the proposed change[1]. Here is a JIRA ticket[2] to track the proposed change, and here is the PR[3] to implement the change. Any thoughts? Cheers, Daniel Sun [1] https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdanielsun1106%2Fgroovy-parser%2Fcommits%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=qdhNufAqJP8kpOtsz1QWwz2b06pR%2F1v5loQnNcuWWRM%3Dreserved=0 [2] https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fissues.apache.org%2Fjira%2Fbrowse%2FGROOVY-9484data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=Z3FyviGcsG4EtvIGiAv889dG%2F2p%2FhqClAED998%2BnT98%3Dreserved=0 [3] https://nam02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fapache%2Fgroovy%2Fpull%2F1211data=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=iXdv8OT3BMIyno8R3TlLclEB1%2BSd%2BxPlCaxhacydSqA%3Dreserved=0 - Apache Groovy committer & PMC member Blog: https://nam02.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.sunlan.medata=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=70Xxc7%2Bg6iF7bhVISTRF48hxQkUb5%2F7iuuofMttDF2o%3Dreserved=0 Twitter: @daniel_sun -- Sent from: https://nam02.safelinks.protection.outlook.com/?url=http%3A%2F%2Fgroovy.329449.n5.nabble.com%2FGroovy-Dev-f372993.htmldata=02%7C01%7Ceric.milles%40thomsonreuters.com%7Cbc5bd8c149104982c52b08d7d2c503df%7C62ccb8646a1a4b5d8e1c397dec1a8258%7C0%7C0%7C637209615925168880sdata=bGnd%2BrQj%2FPKljTtkIdT2fFyGF9aQb0QgR1RzQlWRPsY%3Dreserved=0