You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by Dmitry Semionin <dm...@gmail.com> on 2015/07/18 23:41:10 UTC

Interpolated strings and embedded closures

Hello everybody.

I'm totally new to Groovy, and thought it would be right to start learning
it by studying the online documentation on the official website. One of the
topics i didn't quite understand was the string interpolation in
conjunction with closures.
The documentation offers the following example:

def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" assert
sOneParamClosure == '1 + 2 == 3'

with the following comment: "Here, the closure takes a single
java.io.StringWriter argument, to which you can append content with the <<
leftShift operator."

I have several questions about the code above:

1. Why is w stated to be of type java.io.StringWriter? Why can't it be of
any other type compatible with the << operator, any integer type for
example?
2. The embedded closure from the code above has an argument, but how would
one pass a parameter to such closure? Would doing it even make sense, or
the embedded closures are some special kind that either takes no params or
a single implicit param of type java.io.StringWriter?
3. If there's no way to make such closures have arguments of arbitrary
types and pass parameters to them, then what's the point in such closures
at all? The doc says that closures have a benefit of a lazy variable
evaluation, and that is important, but one doesn't need a parameterized
closure to achieve it. So what am i missing?

I'll be very grateful for any help you guys could provide!

- Dmitry

Re: Interpolated strings and embedded closures

Posted by Jochen Theodorou <bl...@gmx.org>.
Am 19.07.2015 14:47, schrieb Dmitry Semionin:
[...]
> So am i getting it correct that all the embedded closures
> that are declared to have a parameter take an implicit argument of the
> type StringWriter by design? Because that code snippet i mentioned,
>
> def  sOneParamClosure=  "1 + 2 == ${ w -> w << 3}"
> assert  sOneParamClosure==  '1 + 2 == 3'
>
> is self-sufficient in the documentation, and these two statements give
> no reason to assume that there's some variable around named 'w' of type
> StringWriter that was simply bound by the closure. Plus, it would be
> illegal syntax-wise because 'w' in the first statement is the name of
> the argument, which means it has a local visibility scope and refers to
> an argument passed to the closure. Am i wrong here?

{ w -> }

means you declare a "closure" with a parameter of name w. w is not of 
type StringWriter, but the closure will be called with a value of type 
StringWriter, and that will be accessed through w inside the "closure". 
Just imagine you would write this method:

def call(w) { w<<3 }

same deal. In Groovy you don't need always to give a type, which means 
Object will be used as the minimally required type. In other words the 
method declaration above expands to:

def call(Object w) { w<<3}

And def is an alias for Object so:

Object call(Object w) {w<<3}

Similar for {w->w<<3} becoming {Object w->w<<3}

'w' is the name of the parameter, with local visibility scope and allows 
access to the argument of the call.

> So either all the parameterized embedded closures do by design take an
> implicit argument of type StringWriter, or my question remains: how does
> one pass arguments to such closures?

Again you wildly mix arguments and parameters ;) In the example you 
showed, there is no implicit parameter. {w->} is a closure with the 
explicit parameter w. {->} is a closure without parameter

> I mean, let's view it as the manual
> tells us. Here -
> http://www.groovy-lang.org/syntax.html#_string_interpolation - it says
> the following:
>
> The placeholder expressions are surrounded by |${}| or prefixed with |$|
> for dotted expressions. The expression value inside the placeholder is
> evaluated to its string representation when the GString is passed to a
> method taking a String as argument by calling |toString()| on that
> expression.

yes, but... "${x}" is a GString that won't contain a closure, while 
"${w->w<<x}" is one. The syntax for simple interpolation and 
interpolation using closures overlaps

> If the embedded closures are a special case of string interpolation and
> interpolated strings are evaluated upon conversion to regular Java
> strings, then the second statement from the code block above is a place
> where such conversion takes place. So if one can somehow pass an
> argument to the embedded closure, it should be either here or somewhere
> above. But i don't see anything that might count for it.

A GString "foo $bar" (longer form "foo ${bar}"), is a GStringImpl object 
in Groovy, implementing the interface GString and basically consists of 
the String "foo " and a reference to the value of bar. If you call 
toString() on this GString it will execute "foo "+bar.toString() using a 
StringWriter. Meaning each toString call, will cause a new evaluation.

A GString "foo ${w->w<<bar}" will be a GStringImpl like above, also 
having the String "foo ", but then it will have a closure object stored, 
that represents {w->w<<bar}. Instead of doing simply toString() on the 
closure, the implementation give the StringWriter directly to the 
closure, after writing "foo " into it. The code associated with the 
closure will then use << to write the value of bar into the resulting 
String.

To show the differences to String and usage of Closure:

class MyX {
   String val
   String toString() {val}
}

This class will change its toString, whenever val is changed

def x = new MyX(val:"1")
String str0 = "foo "+x // normal String
def str1 = "foo ${x}"  // gstring with value of x
def str2 = "foo ${w->w<<x}" // gstring with reference to x

// all seem to be the same from this test
assert str0 == "foo 1"
assert str1 == "foo 1"
assert str2 == "foo 1"

// changing toString result:
x.val = "2"

// String cannot change, since it is complete already
assert str0 == "foo 1"
// GString is "reinterpreted" for each toString
assert str1 == "foo 2"
assert str2 == "foo 2"

//changing x itself
x = new MyX(val:"3")

// String cannot change, since it is complete already
assert str0 == "foo 1"
// GString here uses the old x
assert str1 == "foo 2"
// Gstring here uses the closure, which references always the new x
assert str2 == "foo 3"

You could say there are three levels of laziness in this. The String 
version does eager evaluation, so it is done only once. GString evals 
every time, but you can store normal objects in there or closures. The 
closures on the other hand can do full lazy evaluation.

An alternative implementation for Closure would have been to let it 
return a String of course. I guess that would have been more easy to 
understand for you. But it is also less powerful.

bye blackdrag

-- 
Jochen "blackdrag" Theodorou
blog: http://blackdragsview.blogspot.com/


Re: Interpolated strings and embedded closures

Posted by Dmitry Semionin <dm...@gmail.com>.
Hi Jochen, and thanks for the reply.

On Sun, Jul 19, 2015 at 9:14 AM, Jochen Theodorou <bl...@gmx.org> wrote:

>
> parameter = variable (with type) declared in a method/closure
> argument  = value (with type) used to call a method/closure
>

Yep, i totally confused the terms 'parameter' and 'argument' with each
other. Thanks for clearing it for me. But, apart from that, the question
still stays.

So it means the closure is called with a value of type StringWriter. The
> parameter can of course have any type that is a parent to StringWriter. No
> type being used means for example Object. But if you supply an incompatible
> type, you will get an exception on call. For example if you give the
> parameter w the type int, then you do have leftShift on there, but the
> method call to the closure itself is still done with a StringWriter and
> will fail.
>

Wait a minute. So am i getting it correct that all the embedded closures
that are declared to have a parameter take an implicit argument of the type
StringWriter by design? Because that code snippet i mentioned,

def  sOneParamClosure=  "1 + 2 == ${ w -> w << 3}"
assert  sOneParamClosure==  '1 + 2 == 3'

is self-sufficient in the documentation, and these two statements give no
reason to assume that there's some variable around named 'w' of type
StringWriter that was simply bound by the closure. Plus, it would be
illegal syntax-wise because 'w' in the first statement is the name of the
argument, which means it has a local visibility scope and refers to an
argument passed to the closure. Am i wrong here?

So either all the parameterized embedded closures do by design take an
implicit argument of type StringWriter, or my question remains: how does
one pass arguments to such closures? I mean, let's view it as the manual
tells us. Here -
http://www.groovy-lang.org/syntax.html#_string_interpolation - it says the
following:

The placeholder expressions are surrounded by ${} or prefixed with $ for
dotted expressions. The expression value inside the placeholder is
evaluated to its string representation when the GString is passed to a
method taking a String as argument by calling toString() on that expression.

If the embedded closures are a special case of string interpolation and
interpolated strings are evaluated upon conversion to regular Java strings,
then the second statement from the code block above is a place where such
conversion takes place. So if one can somehow pass an argument to the
embedded closure, it should be either here or somewhere above. But i don't
see anything that might count for it.

So what am i getting wrong?

- Dmitry

Re: Interpolated strings and embedded closures

Posted by Jochen Theodorou <bl...@gmx.org>.
Am 18.07.2015 23:41, schrieb Dmitry Semionin:
> Hello everybody.
>
> I'm totally new to Groovy, and thought it would be right to start
> learning it by studying the online documentation on the official
> website. One of the topics i didn't quite understand was the string
> interpolation in conjunction with closures.
> The documentation offers the following example:
>
> |def  sOneParamClosure=  "1 + 2 == ${ w -> w << 3}"
> assert  sOneParamClosure==  '1 + 2 == 3'
>
> |
>
> with the following comment: "||Here, the closure takes a single
> |java.io.StringWriter| argument, to which you can append content with
> the |<<| leftShift operator."
>
> I have several questions about the code above:
>
> 1. Why is |w| stated to be of type |java.io.StringWriter|? Why can't it
> be of any other type compatible with the |<<| operator, any integer type
> for example?

parameter = variable (with type) declared in a method/closure
argument  = value (with type) used to call a method/closure

So it means the closure is called with a value of type StringWriter. The 
parameter can of course have any type that is a parent to StringWriter. 
No type being used means for example Object. But if you supply an 
incompatible type, you will get an exception on call. For example if you 
give the parameter w the type int, then you do have leftShift on there, 
but the method call to the closure itself is still done with a 
StringWriter and will fail.

> 2. The embedded closure from the code above has an argument, but how
> would one pass a parameter to such closure?  Would doing it even make
> sense, or the embedded closures are some special kind that either takes
> no params or a single implicit param of type |java.io.StringWriter|?
> 3. If there's no way to make such closures have arguments of arbitrary
> types and pass parameters to them, then what's the point in such
> closures at all? The doc says that closures have a benefit of a lazy
> variable evaluation, and that is important, but one doesn't need a
> parameterized closure to achieve it. So what am i missing?

You have argument and parameter wrong. Does my definition of parameter 
and argument above explain this as well to you?

bye blackdrag

-- 
Jochen "blackdrag" Theodorou
blog: http://blackdragsview.blogspot.com/