G-String embedded Closure calling bug?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
12
Reply | Threaded
Open this post in threaded view
|

G-String embedded Closure calling bug?

Nathan Harvey
Take the following code:

int triggered = 0
def o = { -> triggered++ }
               
println(o) // A
println("$o") // B
println("${o}") // C

After A, triggered is 0; after B, it's 1; after C, it's 2. The Closure is
being called and the result of it is being printed instead. Is this behavior
intended?



--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

paulk_asert
I suspect this is intentional but was before my time. Try this also:

int triggered = 0
def o1 = { -> triggered++ }
def o2 = { println '*' + it; triggered++ }

println(o1) // ConsoleScript11$_run_closure1@xxxxxxxx
println(o2) // ConsoleScript11$_run_closure2@yyyyyyyy

assert triggered == 0
println("xyzzy$o1") // xyzzy0
assert triggered == 1
println("XX${o2}YY${o2(42)}ZZ") // *42\n*XX\nXXYY1ZZ
assert triggered == 3


On Fri, Dec 22, 2017 at 8:20 AM, Nathan Harvey <[hidden email]> wrote:
Take the following code:

int triggered = 0
def o = { -> triggered++ }

println(o) // A
println("$o") // B
println("${o}") // C

After A, triggered is 0; after B, it's 1; after C, it's 2. The Closure is
being called and the result of it is being printed instead. Is this behavior
intended?



--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html

Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

paulk_asert
Or change the last two lines a little more:

println("XX${o2}YY${o2(42)}ZZ$o2")  // *42\n*XX\n*XXYY1ZZ\nXXYY1ZZ
assert triggered == 4

It looks weird to me but perhaps there was a reason to it?


On Fri, Dec 22, 2017 at 9:20 AM, Paul King <[hidden email]> wrote:
I suspect this is intentional but was before my time. Try this also:

int triggered = 0
def o1 = { -> triggered++ }
def o2 = { println '*' + it; triggered++ }

println(o1) // ConsoleScript11$_run_closure1@xxxxxxxx
println(o2) // ConsoleScript11$_run_closure2@yyyyyyyy

assert triggered == 0
println("xyzzy$o1") // xyzzy0
assert triggered == 1
println("XX${o2}YY${o2(42)}ZZ") // *42\n*XX\nXXYY1ZZ
assert triggered == 3


On Fri, Dec 22, 2017 at 8:20 AM, Nathan Harvey <[hidden email]> wrote:
Take the following code:

int triggered = 0
def o = { -> triggered++ }

println(o) // A
println("$o") // B
println("${o}") // C

After A, triggered is 0; after B, it's 1; after C, it's 2. The Closure is
being called and the result of it is being printed instead. Is this behavior
intended?



--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html


MG
Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

MG
I have never wanted to embed a Closure obj in a GString, but the behavior is definitely a bit unexpected.

I must admit that I feel that Groovy features like being able to iterate over null, or that an empty collection is Groovy-true are more of a problem imho. I have never had any application for the latter, but have a lot of code where I have to say

final cols = colsIn != null ? colsIn : defaultCols()

instead of just

final cols = colsIn ?: defaultCols()


Btw has an ?= operator ever been suggested, which assigns the RHS iff the LHS has value null ? If it where also supported for assigning default parameter values one could do:

void foo(final Columns cols ?= defaultCols(), String s) {
  s ?= defaultString()
}

This would allow to pass in null as parameter value which is passed through several calls without the need to duplicate e.g. the cols parameter default value in method definitions, and elegantly assign the default value in the last method called...



-------- Ursprüngliche Nachricht --------
Von: Paul King <[hidden email]>
Datum: 22.12.17 00:25 (GMT+01:00)
Betreff: Re: G-String embedded Closure calling bug?

Or change the last two lines a little more:

println("XX${o2}YY${o2(42)}ZZ$o2")  // *42\n*XX\n*XXYY1ZZ\nXXYY1ZZ
assert triggered == 4

It looks weird to me but perhaps there was a reason to it?


On Fri, Dec 22, 2017 at 9:20 AM, Paul King <[hidden email]> wrote:
I suspect this is intentional but was before my time. Try this also:

int triggered = 0
def o1 = { -> triggered++ }
def o2 = { println '*' + it; triggered++ }

println(o1) // ConsoleScript11$_run_closure1@xxxxxxxx
println(o2) // ConsoleScript11$_run_closure2@yyyyyyyy

assert triggered == 0
println("xyzzy$o1") // xyzzy0
assert triggered == 1
println("XX${o2}YY${o2(42)}ZZ") // *42\n*XX\nXXYY1ZZ
assert triggered == 3


On Fri, Dec 22, 2017 at 8:20 AM, Nathan Harvey <[hidden email]> wrote:
Take the following code:

int triggered = 0
def o = { -> triggered++ }

println(o) // A
println("$o") // B
println("${o}") // C

After A, triggered is 0; after B, it's 1; after C, it's 2. The Closure is
being called and the result of it is being printed instead. Is this behavior
intended?



--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html


Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

Nathan Harvey
Yeah, I don't understand this behavior either. Seems better to write "${o()}"
if you want call it. Anyone against changing that?

MG, yes that operator has been proposed for Parrot, but I'm not sure what
happened to it. Maybe start another thread for it.



--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

Jochen Theodorou
In reply to this post by paulk_asert
On 22.12.2017 00:20, Paul King wrote:

> I suspect this is intentional but was before my time. Try this also:
>
> int triggered = 0
> def o1 = { -> triggered++ }
> def o2 = { println '*' + it; triggered++ }
>
> println(o1) // ConsoleScript11$_run_closure1@xxxxxxxx
> println(o2) // ConsoleScript11$_run_closure2@yyyyyyyy
>
> assert triggered == 0
> println("xyzzy$o1") // xyzzy0
> assert triggered == 1
> println("XX${o2}YY${o2(42)}ZZ") // *42\n*XX\nXXYY1ZZ
> assert triggered == 3

ah yes... good old times with John Wilson... I think the idea was back
then to leverage the Closures for templating engine purposes.. like for
example GStringTemplateEngine the whole template in there is basically a
Closure and writing is channeld by the writeTo method, that is also used
for toString.

I really wonder how much this feature is used. If you look at the code
you will see, that it does lead to very surprising behaviour, for
example toString on Closure and writeTo in GString do not fit very well
together and the GString base evaluation may lead to a double evaluation
by working on the result of the Closure call. Plus of course the
different behaviour for if the closure does or does not take a parameter
where we one time work on the result and one time we ignore the result
and instead let the Closure itself work things out.

Frankly, this is on my list of features to be removed. I have not yet
fully investigated the impact of this - and I suspect there will be much
more impact here than it looks like on first glance

bye Jochen


Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

Daniel.Sun
Hi Jochen,

      As far as I remember,  John Wilson is one of main contributors of
Groovy, he is active in about 2007 and rejected some proposals of mine ;-)

Cheers,
Daniel.Sun



--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Daniel Sun
Apache Groovy committer

Blog: http://blog.sunlan.me
Twitter: @daniel_sun
Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

Jochen Theodorou
On 22.12.2017 16:55, Daniel.Sun wrote:
> Hi Jochen,
>
>        As far as I remember,  John Wilson is one of main contributors of
> Groovy, he is active in about 2007 and rejected some proposals of mine ;-)

he did a lot of work for Groovy 1.0 for example and way before too (with
a gap of quite some time) yes. Which is why it was difficult to argue
against those things back then. Guillaume will remember some of the
heated discussions.

And I am not saying what he did is wrong or stupid. Nothing like that,
no. But the usage of the language changes and we did tend to overload
constructs a bit too much in the past

bye Jochen
Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

Nathan Harvey
In reply to this post by Nathan Harvey
Are there any more thoughts on whether or not this behavior should be
changed? I say it is confusing and unnecessary.  I think it's important to
keep the behavior advertised for Closures intact, eg: "hello {-> 0}" should
still render 0, but a reference to a Closure should not automatically call
toString()



--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
Reply | Threaded
Open this post in threaded view
|

Re: G-String embedded Closure calling bug?

Guillaume Laforge
Administrator
We've settled on that behavior a long time ago, so it's quite blurry in my mind, to be honest.
I'd be a bit afraid of making changes to how things are working now, as it might have some unintended consequences.
I mean, making some changes there could break people's code in unexpected places, and I think it would be pretty hard to track and find.
With age (not that I'm old, but I've been involved in Groovy for 14 years now), I become a bit more conservative, and afraid of making anything that could be breaking people's code :-(

Guillaume


On Sun, Dec 31, 2017 at 4:57 AM, Nathan Harvey <[hidden email]> wrote:
Are there any more thoughts on whether or not this behavior should be
changed? I say it is confusing and unnecessary.  I think it's important to
keep the behavior advertised for Closures intact, eg: "hello {-> 0}" should
still render 0, but a reference to a Closure should not automatically call
toString()



--
Guillaume Laforge
Apache Groovy committer & PMC Vice-President
Developer Advocate @ Google Cloud Platform

12