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/

Reply via email to