[groovy-user] ternary operator in gstring?

537 views
Skip to first unread message

Ray Tayek

unread,
Jun 12, 2008, 1:40:47 AM6/12/08
to us...@groovy.codehaus.org
hi, i was trying to use the ternary operator in a gstring (to deal
with a blank or null second line of an address). the code below seems
to work. is it supposed to work this way or did i just get lucky?

thanks

def p={a,b->
def x=b?", ${b}":''
println "${a}${x}"
println "${a}${b?(", $b"):''}"
}
p('foo','bar')
p('foo','')
p('foo',null)

---
vice-chair http://ocjug.org/

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Jim White

unread,
Jun 12, 2008, 2:17:39 AM6/12/08
to us...@groovy.codehaus.org
Groovy is indeed a source of neverending surprises.

I just posted a GString solution ("XML Transformation") and I would have
told you that GStrings *don't* work that way because I assumed nested
literals in GString ${} expressions would need escaping.

There can be little doubt the behavior is intentional but I don't know
where it is documented (and too lazy to dig out GinA right now).

Notice that this nesting appears to work for all string literal
syntaxes. So the way to view this is that ${} introduces recursion in
the parse, not that the whole string is first a literal and then ${}
expressions recognized.

assert 'A' == "${"A"}"
assert 'AB' == "${"A${"B"}"}"
assert 'A\tB\tC' == "${"A\tB" + '\t'}C"
assert 'A\\tB\tC' == "${/A\tB/ + '\t'}C" // !
assert 'A' == """${"A"}"""
assert 'AB' == """${"A${"B"}"}"""
assert 'A\tB\tC' == """${"A\tB" + new String('\t')}C"""
assert 'A' == /${"A"}/
assert 'AB' == /${"A${"B"}"}/
assert 'A\tB\tC' == /${"A\tB" + '\t'}C/
assert 'A' == /${/A/}/
assert 'AB' == /${/A${/B/}/}/
assert 'A\\tB\tC' == /${/A\tB/ + '\t'}C/

Jim

Guillaume Laforge

unread,
Jun 12, 2008, 4:17:54 AM6/12/08
to us...@groovy.codehaus.org
You can put any Groovy expression inside a GString.

Even statements!
"${println "hello"; 'foobar'}"

So, yes, you can put the ternary op, or Elvis too :-)

--
Guillaume Laforge
Groovy Project Manager
G2One, Inc. Vice-President Technology
http://www.g2one.com

Jim White

unread,
Jun 12, 2008, 4:54:01 AM6/12/08
to us...@groovy.codehaus.org
Guillaume Laforge wrote:

> You can put any Groovy expression inside a GString.
>
> Even statements!
> "${println "hello"; 'foobar'}"
>
> So, yes, you can put the ternary op, or Elvis too :-)

Although Ray mentioned ternary operator in the subject, that isn't the
surprise (at least not to me, and I'm pretty sure Ray knows you can put
things other than variable names in ${}).

The issue is that the expression within the ${} also contains a GString
and there is no escaping involved.

For folks who thought of the ${} within a GString as being parsed
"after" the literal is parsed, that is unexpected. See my other post.

Jim

Jochen Theodorou

unread,
Jun 12, 2008, 6:37:09 AM6/12/08
to us...@groovy.codehaus.org
Ray Tayek schrieb:

> hi, i was trying to use the ternary operator in a gstring (to deal with
> a blank or null second line of an address). the code below seems to
> work. is it supposed to work this way or did i just get lucky?
>
> thanks
>
> def p={a,b->
> def x=b?", ${b}":''
> println "${a}${x}"
> println "${a}${b?(", $b"):''}"
> }
> p('foo','bar')
> p('foo','')
> p('foo',null)

b?x:y

tests if b is false, null, or empty, where empty stands for example for
an empty Map, List or String. In these cases y is executed, in the other
cases x. Not sure if that was what you asked for

bye blackdrag


--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

Jochen Theodorou

unread,
Jun 12, 2008, 6:42:09 AM6/12/08
to us...@groovy.codehaus.org
Jim White schrieb:

> Groovy is indeed a source of neverending surprises.
>
> I just posted a GString solution ("XML Transformation") and I would have
> told you that GStrings *don't* work that way because I assumed nested
> literals in GString ${} expressions would need escaping.
>
> There can be little doubt the behavior is intentional but I don't know
> where it is documented (and too lazy to dig out GinA right now).

I am pretty sure GinA for example mentions, that you need to escape $ in
GStrings if you do not want this recursion.

> Notice that this nesting appears to work for all string literal
> syntaxes.

It should work for ", """, /, but not for ' and '''. So not all.

> So the way to view this is that ${} introduces recursion in
> the parse, not that the whole string is first a literal and then ${}
> expressions recognized.

what would be the difference?

bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

---------------------------------------------------------------------

Jim White

unread,
Jun 12, 2008, 9:46:10 AM6/12/08
to us...@groovy.codehaus.org
Jochen Theodorou wrote:

> Jim White schrieb:
>
>> Groovy is indeed a source of neverending surprises.
>>
>> I just posted a GString solution ("XML Transformation") and I would
>> have told you that GStrings *don't* work that way because I assumed
>> nested literals in GString ${} expressions would need escaping.
>>
>> There can be little doubt the behavior is intentional but I don't know
>> where it is documented (and too lazy to dig out GinA right now).
>
> I am pretty sure GinA for example mentions, that you need to escape $ in
> GStrings if you do not want this recursion.

I've now examined all the GinA pages indexed for GString and the nature
of this recursion wrt nested string literal syntax is not documented.
That is not surprising because if it had been mentioned, I would have
noticed because it so unusual.

There is this example (the footnote at the bottom of page 70) talking
about how to workaround the problem of putting a \ in a slashy:

/${'\\'}/

So an eagle-eyed reader might infer that something interesting is going
on, but there is no explanation or details and the context is so
specific that one is unlikely to pick up on the general rule from it.

Also the examples for GStringTemplate (pages 311-312) also have single
quote literals within ${} expressions, but they are only ' ' or '' and
so are entirely ambiguous wrt to this issue.

As you say, the text and Table 3.6 on page 71 does state that $ can be
escaped in GStrings to get a literal $ rather than a ${} expression, but
that isn't what I'm talking about here at all.

>> Notice that this nesting appears to work for all string literal syntaxes.
>
> It should work for ", """, /, but not for ' and '''. So not all.

It does work for ' and ''' as I showed in my tests. Naturally not being
a GString though, there can't be any further nesting.

This pair of examples is highly instructive as it shows the escaping
syntax to be that of the innermost string literal rather than the
outtermost:

assert 'A\\tB\tC' == "${/A\tB/ + '\t'}C"

assert 'A\tB\tC' == /${"A\tB" + '\t'}C/

>> So the way to view this is that ${} introduces recursion in the parse,

>> not that the whole string is first a literal and then ${} expressions
>> recognized.
>
> what would be the difference?

Writing ${} expressions with string literals would be much more
difficult otherwise. Kind of like writing regex without slashy but even
more awkward.

The example above (which isn't a very difficult case) would look like this:

assert 'A\\tB\tC' == "${/A\\tB/ + '\\t'}C"

So it is a very convenient feature, but quite unlike the string literals
of most languages I can think of. It is quite a bit like the XML
literals of XQuery though.

Jim

Erick Erickson

unread,
Jun 12, 2008, 11:25:51 AM6/12/08
to us...@groovy.codehaus.org
The ternary op that's surprised me lately is

z = x?:y

which assigns x to z if x in not-null, else it assigns y.

Incidentally, speaking of surprises late in life, I had
no idea until recently that Java allows
& or | to be boolean operators if both
operands are of type Boolean. So
if (bool & bool)

is equivalent to

if (bool && bool)

and is NOT a bitwise and operator no matter what
old C programmers think <G>.

Best
Erick

tugwilson

unread,
Jun 12, 2008, 12:37:45 PM6/12/08
to us...@groovy.codehaus.org

I believe the lexer treats "some text${ as "some text" and } some more text"
as "some text"

so "some text${ a + b } some more text" is almost like the Java "some text"
+ (a + b) + "some text"

It's different because the expression is evaluated at the point that the
GString is created but the concatenation is delayed until the GString is
evaluated.

Did you know that there is a special case if a zero or one parameter closure
follows $?

With "some text${-> a + b } some more text" (i.e. a zero parameter closure
follows $) the closure is saved in the GString object and is called every
time the GString is evaluated and the result interpolated into the resulting
set of characters.

With "some text${out -> out << (a + b) } some more text" (i.e. a one
parameter closure follows $) the closure is saved in the GString object and
is called every time the GString is evaluated with a Writer passed as the
parameter. Whatever is written to the Writer is interpolated into the
resulting set of characters.

This makes GStrings a pretty powerful templating mechanism on its own.

John Wilson
--
View this message in context: http://www.nabble.com/ternary-operator-in-gstring--tp17792868p17804307.html
Sent from the groovy - user mailing list archive at Nabble.com.

Jochen Theodorou

unread,
Jun 12, 2008, 3:50:18 PM6/12/08
to us...@groovy.codehaus.org
Jim White schrieb:

> Jochen Theodorou wrote:
>
>> Jim White schrieb:
[...]

>>> Notice that this nesting appears to work for all string literal
>>> syntaxes.
>>
>> It should work for ", """, /, but not for ' and '''. So not all.
>
> It does work for ' and ''' as I showed in my tests. Naturally not being
> a GString though, there can't be any further nesting.

I guess we have a misunderstanding here... "$a" is a GString, but '$a'
is not. meaning, "${"$a"}"=="$a", but "${'$a'}". since youcan use *any*
expression inside ${}, I don't see why you point the string literals out
so much.

[...]


>>> So the way to view this is that ${} introduces recursion in the
>>> parse, not that the whole string is first a literal and then ${}
>>> expressions recognized.
>>
>> what would be the difference?
>
> Writing ${} expressions with string literals would be much more
> difficult otherwise. Kind of like writing regex without slashy but even
> more awkward.

I somehow get the feeling this is like talking about () and comparing it
to cases where you can not nest the ()... which do not exist.

> The example above (which isn't a very difficult case) would look like this:
>
> assert 'A\\tB\tC' == "${/A\\tB/ + '\\t'}C"

ah, ok, I get it...well.. like for (), what is inside of ${} can be any
expression

bye blackdrag

--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

---------------------------------------------------------------------

Jim White

unread,
Jun 12, 2008, 4:09:01 PM6/12/08
to us...@groovy.codehaus.org
Jochen Theodorou wrote:

> Jim White schrieb:
>
>> Jochen Theodorou wrote:
>>
>>> Jim White schrieb:
>
> [...]
>
>>>> Notice that this nesting appears to work for all string literal
>>>> syntaxes.
>>>
>>>
>>> It should work for ", """, /, but not for ' and '''. So not all.
>>
>>
>> It does work for ' and ''' as I showed in my tests. Naturally not
>> being a GString though, there can't be any further nesting.
>
>
> I guess we have a misunderstanding here... "$a" is a GString, but '$a'
> is not. meaning, "${"$a"}"=="$a", but "${'$a'}". since youcan use *any*
> expression inside ${}, I don't see why you point the string literals out
> so much.
> ...

For the purposes of documentation. There is the hope that one day
Groovy will have a language specification...

Jim

Ray Tayek

unread,
Jun 12, 2008, 5:03:51 PM6/12/08
to us...@groovy.codehaus.org
At 08:25 AM 6/12/2008, you wrote:
>... I had

>no idea until recently that Java allows
>& or | to be boolean operators if both
>operands are of type Boolean. So
>if (bool & bool)
>
>is equivalent to
>
>if (bool && bool)
>
>and is NOT a bitwise and operator no matter what

they are different: http://en.wikipedia.org/wiki/Short-circuit_evaluation

thanks

---
vice-chair http://ocjug.org/

Detering Dirk

unread,
Jun 13, 2008, 2:35:44 AM6/13/08
to us...@groovy.codehaus.org
> From: Erick Erickson

> The ternary op that's surprised me lately is
>
> z = x?:y
>
> which assigns x to z if x in not-null, else it assigns y.

Well, that is indeed the Elvis Operator, often talked about.

BTW: It is applicable as a good constraints checker too.


def throwErr(prop) {
throw new ImportantPropertyNotSetException("Mandatory Property $prop
not set!")
}


def init() {
valA = getProperty("A") ?: throwErr("A")
valB = getProperty("B") ?: throwErr("B")
valC = getProperty("C") ?: throwErr("C")
...
}

***********************************************************************

Die Information in dieser email ist vertraulich und ist ausschliesslich
fuer den/die benannten Adressaten bestimmt. Ein Zugriff auf diese
email durch andere Personen als den/die benannten Adressaten ist
nicht gestattet. Sollten Sie nicht der benannte Adressat sein, loeschen
Sie bitte diese email.

***********************************************************************

BITMARCK Software GmbH
Paul-Klinger-Strasse 15, 45127 Essen

Amtsgericht Essen HRB 20680
Geschaeftsfuehrer: Frank Krause, Andreas Prenneis

Erick Erickson

unread,
Jun 13, 2008, 9:25:26 AM6/13/08
to us...@groovy.codehaus.org
Yes, there is a difference, that the &, | and ^ operators
always evaluate both sides.

But you missed the point entirely. The point I was trying
to make was that there existed at all operators & | and ^
that worked on boolean values in Java. Which, from an old
C programmers perspective is something of a surprise.

See O'Reilly's, "Java in a Nutshell", 3rd ed, pp. 38-39,
where it discusses Boolean AND/OR/XOR and bitwise
AND/OR/XOR, in both cases represented by & | and ^.
Which sense is used depends entirely upon whether
the operands are Booleans or Integers.

And I flat guarantee that, contrary to the Wikipedia
article, the & and | operators are NOT, in any way,
shape, or form, equivalent to Boolean operators in
C or C++ in practice. They are bitwise operators.
Which  sometimes gives behavior similar to Boolean
ops. For a while. Until the demo. As I've found through
waaaaay too many hours of debugging typos where
I intended && but typed &......

I thought this bit from O'Reilly interesting from the Boolean AND
(&) discussion... "...and many Java programmers would not even
recognize its use with boolean operands as legal Java code."
Count me in that group until relatively recently......

Best
Erick

Ray Tayek

unread,
Jun 13, 2008, 7:55:30 PM6/13/08
to us...@groovy.codehaus.org
At 06:25 AM 6/13/2008, you wrote:
>Yes, there is a difference, that the &, | and ^ operators
>always evaluate both sides.
>
>But you missed the point entirely. The point I was trying
>to make was that there existed at all operators & | and ^
>that worked on boolean values in Java.

oh, i see.

> Which, from an old
>C programmers perspective is something of a surprise.

i am an old c programmer also. i got lucky, because we went over all
the operators in the jls in the java course i took, so i sorta
absorbed that way back then.

>See O'Reilly's, "Java in a Nutshell", 3rd ed, pp. 38-39,
>where it discusses Boolean AND/OR/XOR and bitwise
>AND/OR/XOR, in both cases represented by & | and ^.
>Which sense is used depends entirely upon whether
>the operands are Booleans or Integers.
>
>And I flat guarantee that, contrary to the Wikipedia
>article, the & and | operators are NOT, in any way,
>shape, or form, equivalent to Boolean operators in
>C or C++ in practice. They are bitwise operators.

i must be miss interpreting what i am reading. these work fine in
java or groovy:

int x=2;
int y=1;
int z=x|y;
System.out.println(z);

this will print out 3 as expected.

sorry to be so dense :(

Erick Erickson

unread,
Jun 13, 2008, 8:19:44 PM6/13/08
to us...@groovy.codehaus.org
I think we're talking past each other here. It was just a little joke on me that I
was trying to tell.

Sure, int | int behaves like a bitwise OR since it is one as the operands are ints.
and bool | bool behaves like a logical OR since it is as the operands are booleans.
In Java at least.

I'm not trying to assert that anything is behaving improperly, except possibly my
brain since it *still* has old C reflexes apparently.

Anyway, I think this is beaten to death now.

Best
Erick
Reply all
Reply to author
Forward
0 new messages