jastrachan | 4 Mar 08:26 2005
Picon

brace placement - a possible solution

The topic of { brace placement has come up recently on the lists so I 
thought I'd briefly outline the issues involved and propose a solution.

Use case
=======
Many developers wish to use arbitrary brace placement, aligning braces 
on newlines like you can do in Java and C/C++

Background
=========
Before we start, a little background. So far we've had a rule, rather 
like Ruby, JavaScript and most other scripting languages that says if a 
statement is valid when a newline is reached, the statement is 
considered to be terminated. i.e. its like the compiler added a ; at 
the end of the line for you.

e.g.

x = y + 1 	// implicit ; goes here
z = y +
5		// implicit ; goes here as the previous line wasn't complete

In general this works well and is a natural rule when people use shells 
and scripting languages.

However in Groovy we use { a fair bit, its a very magical token and the 
mixture of newlines and { can lead to ambiguities - particularly with 
closure passing syntax on method invocations.

Up to now we've tried to encourage people to use { on the same line its 
used to try minimise the ambiguities involved. There's clearly been 
some fairly emotional push back on this (I myself used to once, back in 
the C++ days, use brace-alignment, it was good practice back then as 
compilers mostly sucked - though I've since switched to K&R / Sun 
style, something that's actually quite painless once you've been 
through it, but I do sympathise with folks who find K&R/Sun style 
jarring on the eye).

So lets walk through the ambiguities and see if we can come up with an 
amendment to the newline handling in Groovy that makes the brace-align 
camp happier...

Ambiguities involved
================

The main issue here is that { can be appended to something which looks 
like a valid statement; so as soon as a newline is used before { a few 
different meanings could be inferred.

Consider this method

def something() {
     foo.bar()   {
     ...
     }
}

To groovy folks the meaning looks clear.

However as soon as we introduce a newline

def something() {
     foo.bar()
     {
     ...
     }
}

we now have 3 possible interpretations...

1) its a method call with a closure parameter (just like the previous 
example)
2) its a method call then its an implicit return of a closure from the 
'something' method
3) its a method call then afterwards its a free standing block

Now for some time free standing blocks have been ambiguous in groovy 
due to { being such a special character; we discussed this at the JSR 
meeting at length and basically we've long pushed back on them - so 
currently free standing blocks are not allowed unless

(i) a label is used

myblock: {
// free standing block
}

(ii) a regular keyword is used

if (true) {
// free standing block
}

(iii) we could consider adding a new keyword for free standing blocks. 
Personally I don't find that free standing blocks (i.e. a block not 
associated with a method declaration, if/for/while/switch statement or 
closure expression) are particularly useful (I rarely ever use them) so 
I don't think they deserve a special keyword.

So either (i) or (ii) is fine with me since they are so uncommon that a 
little bit more verbosity to use them seems a reasonable trade off.

This now leaves an ambiguity with 1 and 2. Now folks from a Java / C++ 
background often read

foo.bar() {
...
}

and

foo.bar()
{
...
}

to be the same thing; so I'm thinking the Groovy parser should choose 1 
by default as choosing 2 could be surprising.

Proposed Solution
==============

So to solve this use case, if we amended the newline handling in the 
parser to say that

* all newlines are always eaten up by the parser before a {

It basically means that whenever in the grammar a { token could come 
next, newlines are implicitly eaten.  So code can be written using any 
brace placement.

This does complicate a little the explanation of the newline rule in 
Groovy but it does avoid religious brace placement arguments which do 
seem to plague Java/C/C++ languages. (Part of me kinda wanted to put an 
end to these arguments by mandating a placement rule in the language 
but considering the push back this would probably cause - and indeed 
has already caused so far - I don't think I dare :)

This means folks could write code like this

class Foo
{
     Object cheese()
     {
	if (true)
	{
	    bar.whatnot
	    {
		...
	    }
	}
	x.blah(1, 2, 3)
	{
	    // this is a closure
	}
     }
}

putting the { on the previous line in K&R / Sun style would have the 
same meaning.

Implications
=========

The implications of this rule are that if you want to return a closure 
from a method, you must either

(i) use an explicit return/continue statement
(ii) use a semicolon
(iii) use parenthesis

e.g.

def methodWhichReturnsClosure() {
     { ... }
}

def methodWhichReturnsClosure() {
     foo.bar()
     return { ... }
}

def methodWhichReturnsClosure() {
     foo.bar(); { ... }
}

def methodWhichReturnsClosure() {
     foo.bar()
     ({ ... })
}

closureWhichReturnsClosure = { println "hey $it"; { ... } }

All of which mean what I think most groovy folks would think when they 
look at them.

The other implication is, if you want a free standing block, you must 
currently use either a label or an if (true) statement.

void methodWithFreeStandingBlock() {
     foo.bar()
     block: {
	// free standing block here
     }
}

void methodWithFreeStandingBlock() {
     foo.bar()
     if (true) {
	// free standing block here
     }
}

On balance I think the downsides of this proposal are fairly minimal; 
they impact fairly uncommon edge cases while solving a common use case 
(folks who wanna align their braces however they want).

So if we're all happy with the above, we could avoid the brace 
placement arguments once and for all (which I think is a worthy goal 
:).

Thoughts?

James
-------
http://radio.weblogs.com/0112098/


Gmane