[groovy-user] GStrings and placeholder binding

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

[groovy-user] GStrings and placeholder binding

Russel Winder
This is almost certainly just my misunderstanding but...

The following script:

        def number  = 1
        def string = "The number is ${number}"
        number = 20
        println ( string )
        ( 1..10 ).each { number = it ; print ( number + "  " ) ; println ( string ) }
     
produces the output:

        The number is 1
        1  The number is 1
        2  The number is 1
        3  The number is 1
        4  The number is 1
        5  The number is 1
        6  The number is 1
        7  The number is 1
        8  The number is 1
        9  The number is 1
        10  The number is 1

This means that number has been bound to 1 at the point of definition of
string.  However, the documentation says the expression within ${...} is
evaluated lazily, i.e. at the point of use.  This would imply that the
result should either be:

        The number is 20
        1  The number is 20
        2  The number is 20
        3  The number is 20
        4  The number is 20
        5  The number is 20
        6  The number is 20
        7  The number is 20
        8  The number is 20
        9  The number is 20
        10  The number is 20
       
or
       
        The number is 20
        1  The number is 1
        2  The number is 2
        3  The number is 3
        4  The number is 4
        5  The number is 5
        6  The number is 6
        7  The number is 7
        8  The number is 8
        9  The number is 9
        10  The number is 10
       
All three possible results above are perfectly viable semantics but the
documentation had led me to an expectation other than what happened.
--
Russel.
====================================================
Dr Russel Winder                +44 20 7585 2200
41 Buckmaster Road              +44 7770 465 077
London SW11 1EN, UK             [hidden email]

signature.asc (196 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [groovy-user] GStrings and placeholder binding

tugwilson

On 10 Nov 2005, at 09:02, Russel Winder wrote:

> This is almost certainly just my misunderstanding but...
>
> The following script:
>
>         def number  = 1
>         def string = "The number is ${number}"
>         number = 20
>         println ( string )
>         ( 1..10 ).each { number = it ; print ( number + "  " ) ;  
> println ( string ) }
>
> produces the output:
>
>         The number is 1
>         1  The number is 1
>         2  The number is 1
>

> [snip]

> This means that number has been bound to 1 at the point of  
> definition of
> string.  However, the documentation says the expression within $
> {...} is
> evaluated lazily, i.e. at the point of use.  This would imply that the
> result should either be:
>
>         The number is 20
>         1  The number is 20
>         2  The number is 20
> [snip]

> All three possible results above are perfectly viable semantics but  
> the
> documentation had led me to an expectation other than what happened.

This is a little difficult to explain, but....

A GString is not a closure over the environment in which it is  
declared. What happens is that the expressions are evaluated at the  
point of declaration and the result is saved in the GString object.
When the GString is converted to a String then each of the saved  
objects are converted to a String by calling toString() and the  
results are used to create the String vaue of the GString
  If the GString is written out then writeTo is called on the GString  
object (because GStrings are Writable) in this case if any of the  
embedded objects are Writable then writeTo is called on them  
otherwise toString is called.

So what is evaluated lazily is the toString or writeTo function not  
the expression.

def string "The number is: ${{ it << number}.asWritable()}"

should exhibit the behaviour you expect.


John Wilson
The Wilson Partnership
http://www.wilson.co.uk


Reply | Threaded
Open this post in threaded view
|

Re: [groovy-user] GStrings and placeholder binding

Jochen Theodorou
John Wilson schrieb:
[...]
> So what is evaluated lazily is the toString or writeTo function not  the
> expression.
>
> def string "The number is: ${{ it << number}.asWritable()}"
>
> should exhibit the behaviour you expect.

that's not intuitive, we should change that

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

Re: [groovy-user] GStrings and placeholder binding

tugwilson

On 10 Nov 2005, at 09:50, Jochen Theodorou wrote:

> John Wilson schrieb:
> [...]
>> So what is evaluated lazily is the toString or writeTo function  
>> not  the expression.
>> def string "The number is: ${{ it << number}.asWritable()}"
>> should exhibit the behaviour you expect.
>
> that's not intuitive, we should change that

That's something of a value judgement :)

It's really rather valuable behaviour and there is working code in  
the field which depends on it.

I'd like to get rid of the need to call asWritable as this would  
clean up the closure code - but that's a separate discussion!



John Wilson
The Wilson Partnership
http://www.wilson.co.uk


Reply | Threaded
Open this post in threaded view
|

Re: [groovy-user] GStrings and placeholder binding

Jochen Theodorou
John Wilson schrieb:
[...]
> It's really rather valuable behaviour and there is working code in  the
> field which depends on it.

there is code that depends on:

def n = 1
def s= "$n"
n=2
assert "1"==s.toString()

?

Or why can't we return a string for "$n" instead?


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

Re: [groovy-user] GStrings and placeholder binding

tugwilson

On 10 Nov 2005, at 10:16, Jochen Theodorou wrote:

> there is code that depends on:
>
> def n = 1
> def s= "$n"
> n=2
> assert "1"==s.toString()


Probably.

But the code you commented on was showing the behaviour of the  
GString when the embedded object is writeable. I thought you wanted  
to change that behaviour - I *know* there's code which depends on  
that behaviour.

I'm a little confused now:)

What behaviour would you like to change?


John Wilson
The Wilson Partnership
http://www.wilson.co.uk


Reply | Threaded
Open this post in threaded view
|

Re: [groovy-user] GStrings and placeholder binding

Jochen Theodorou
John Wilson schrieb:
>
> On 10 Nov 2005, at 10:16, Jochen Theodorou wrote:
>
>> there is code that depends on:
>>
>> def n = 1
>> def s= "$n"
>> n=2
>> assert "1"==s.toString()
[...]
> What behaviour would you like to change?

the above... it should be "2" not "1"

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

Re: [groovy-user] GStrings and placeholder binding

Russel Winder
In reply to this post by tugwilson
On Thu, 2005-11-10 at 09:30 +0000, John Wilson wrote:

> def string "The number is: ${{ it << number}.asWritable()}"
>
> should exhibit the behaviour you expect.

Not quite:

./gstring.groovy: 13: Closure expression looks like it may be an
isolated open block.;
   solution: Add an explicit parameter list, as in {it -> ...}, or label
it as L:{...}. @ line 13, column 27.
   def a = "The number is ${ { it << number}.asWritable ( ) }"

but that is trivially fixable.  However, I must be being stupid today
(OK, I know, a regular occurrence), but I don't see what is going on.
Clearly the closure gets executed at use time not definition time but
who provides the parameter object?  And what type is it.  << I know from
C++, I have come across it before in Groovy.

--
Russel.
====================================================
Dr Russel Winder                +44 20 7585 2200
41 Buckmaster Road              +44 7770 465 077
London SW11 1EN, UK             [hidden email]

signature.asc (196 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [groovy-user] GStrings and placeholder binding

tugwilson

On 10 Nov 2005, at 13:16, Russel Winder wrote:

> Not quite:
>
> ./gstring.groovy: 13: Closure expression looks like it may be an
> isolated open block.;
>    solution: Add an explicit parameter list, as in {it -> ...}, or  
> label
> it as L:{...}. @ line 13, column 27.
>    def a = "The number is ${ { it << number}.asWritable ( ) }"
>
> but that is trivially fixable.  However, I must be being stupid today
> (OK, I know, a regular occurrence), but I don't see what is going on.
> Clearly the closure gets executed at use time not definition time but
> who provides the parameter object?  And what type is it.  << I know  
> from
> C++, I have come across it before in Groovy.


Sorry about that - the compiler is rather annoying with closures at  
the moment!

'it" is the default name for the parameter passed to the closure.

myList.each{ println it}

prints all the elements of the list



John Wilson
The Wilson Partnership
http://www.wilson.co.uk


Reply | Threaded
Open this post in threaded view
|

Re: [groovy-user] GStrings and placeholder binding

tugwilson
In reply to this post by Jochen Theodorou

On 10 Nov 2005, at 12:48, Jochen Theodorou wrote:

> John Wilson schrieb:
>> On 10 Nov 2005, at 10:16, Jochen Theodorou wrote:
>>> there is code that depends on:
>>>
>>> def n = 1
>>> def s= "$n"
>>> n=2
>>> assert "1"==s.toString()
> [...]
>> What behaviour would you like to change?
>
> the above... it should be "2" not "1"

Ok I understand now.

You are proposing to make a GString a closure over the environment in  
which it is declared.

If we were starting from scratch then it would be worth consideration  
- however the behaviour of GString has been fixed for a couple of  
years and I'm sure that this change would break stuff.


GString are mutable (see getValues() )so the nature of the object  
held to represent "$n" is visible. It's not safe to change it.  
(Groovy SQL makes use of this IIRC)


John Wilson
The Wilson Partnership
http://www.wilson.co.uk


12345