Alternate for-loop form?

551 views
Skip to first unread message

Aston Motes

unread,
Sep 4, 2012, 6:45:24 PM9/4/12
to golan...@googlegroups.com
It seems like there's a missing for-loop form in Go that makes it a pain to emulate while loops as in other languages when dealing with multiple return values. Specifically, I wanted something like this to work (inspired by the syntax for if-statements and the "comma ok" idiom):

for x, done := returns_multiple(); !done {
// do stuff
}

It seems like my two existing options for pulling this off are as follows:

for {
x, done := returns_multiple()
if done {
break
}
//do stuff
}

for x, done:= returns_multiple();!done;x, done = returns_multiple() {
//do stuff
}

Both of those seem to add a lot of noise to something reasonably simple. I'd argue that the syntax of this new form intuitively suggests what would happen if you omitted the third section of the typical for-loop. And I don't think there are any other meanings of a two clause for-loop that would cause confusion for users or would break currently working Go code.

Is this something that could be added to a later version of the language? Also, apologies if this has been proposed before. Searching the archives for terms like "for" and "if" doesn't work super well.

  - Aston

Andrew Gerrand

unread,
Sep 4, 2012, 7:49:56 PM9/4/12
to Aston Motes, golan...@googlegroups.com
To get this straight in my mind, are you proposing that this new syntax

for x, y := fn(); !y {

be equivalent to this statement

for x, y := fn(); !y; x, y = fn() {

? I agree that this seems a natural syntax for what you propose.

But the problem I see is that

for x, y := fn(); !y; {

is a valid statement, is only different from the first statement by
one semicolon, and means something quite different. The potential for
error here is great.

Andrew

Aston Motes

unread,
Sep 4, 2012, 8:39:38 PM9/4/12
to Andrew Gerrand, golan...@googlegroups.com
Yup, you're understanding the proposal correctly. I agree it's not great that just adding a semicolon would change the behavior so much, but it seems like it'd be more natural to write the for loop case with an empty third section as

x, y := fn()
for !y {
...
}

Not sure I'm advocating for adding this new syntax AND disallowing something that's been allowed in C-like languages forever, but if the confusion between the two were a real blocker, it seems like the world wouldn't end disallowing an empty third section. Could "go fix" repair that sort of thing?

  - Aston

Andrew Gerrand

unread,
Sep 4, 2012, 8:58:13 PM9/4/12
to Aston Motes, golan...@googlegroups.com
On 5 September 2012 10:39, Aston Motes <ast...@gmail.com> wrote:
> Yup, you're understanding the proposal correctly. I agree it's not great
> that just adding a semicolon would change the behavior so much, but it seems
> like it'd be more natural to write the for loop case with an empty third
> section as
>
> x, y := fn()
> for !y {
> ...
> }
>
> Not sure I'm advocating for adding this new syntax AND disallowing something
> that's been allowed in C-like languages forever, but if the confusion
> between the two were a real blocker, it seems like the world wouldn't end
> disallowing an empty third section. Could "go fix" repair that sort of
> thing?

Our hands are tied for Go 1. Any language changes must not affect existing code.

http://golang.org/doc/go1compat.html

To be honest, I don't think the proposed change is worth the trouble.

Andrew

Nigel Tao

unread,
Sep 5, 2012, 12:21:38 AM9/5/12
to Aston Motes, Andrew Gerrand, golan...@googlegroups.com
On 5 September 2012 10:39, Aston Motes <ast...@gmail.com> wrote:
> Not sure I'm advocating for adding this new syntax AND disallowing something
> that's been allowed in C-like languages forever, but if the confusion
> between the two were a real blocker, it seems like the world wouldn't end
> disallowing an empty third section.

I saw some Go code only yesterday that had an empty third section.
https://codereview.appspot.com/6492076/diff/8001/src/pkg/strings/replace.go
line 157 is
for i := 0; i < len(s); {

But as adg said, backwards compat means that we can't disallow an
empty third section, and the potential confusion between that and a
two-part for is too high.

Rémy Oudompheng

unread,
Sep 5, 2012, 2:07:48 AM9/5/12
to Aston Motes, golan...@googlegroups.com
On 2012/9/5 Aston Motes <ast...@gmail.com> wrote:
> It seems like there's a missing for-loop form in Go that makes it a pain to
> emulate while loops as in other languages when dealing with multiple return
> values. Specifically, I wanted something like this to work (inspired by the
> syntax for if-statements and the "comma ok" idiom):
>
> for x, done := returns_multiple(); !done {
>
> // do stuff
>
> }
>
> It seems like my two existing options for pulling this off are as follows:
>
> for {
>
> x, done := returns_multiple()
> if done {
>
> break
>
> }
> //do stuff
>
> }
>
> for x, done:= returns_multiple();!done;x, done = returns_multiple() {
>
> //do stuff
>
> }

You have forgotten:

var x T
action = func() (done bool) { x, done := returns_multiple(); return }
for !action() {
// do something...
}

If you don't like your multiple return value function, don't use a
multiple return value function.

> Both of those seem to add a lot of noise to something reasonably simple. I'd
> argue that the syntax of this new form intuitively suggests what would
> happen if you omitted the third section of the typical for-loop. And I don't
> think there are any other meanings of a two clause for-loop that would cause
> confusion for users or would break currently working Go code.

A language construct can be confusing even when it has a single
meaning. I don't understand how it can ever become natural to me that
something that looks like an initialisation statement (like in all
other 2-clause construct we have: switch, select, if...) is supposed
to be repeated.

Rémy.

Dan Kortschak

unread,
Sep 5, 2012, 4:44:24 AM9/5/12
to Rémy Oudompheng, Aston Motes, golan...@googlegroups.com
It does however look a lot like a range statement.

Dan

Rob Pike

unread,
Sep 5, 2012, 8:05:50 AM9/5/12
to Dan Kortschak, Rémy Oudompheng, Aston Motes, golan...@googlegroups.com
That proposal was made early in the development of Go and rejected
because of the huge semantic weight carried by the single tiny
semicolon.

-rob

Jonathan

unread,
Sep 5, 2012, 10:21:02 AM9/5/12
to golan...@googlegroups.com
For what it's worth, if it's worth it at all, this seems best done by adding a while statement that takes a simple statement in the condition:

while ( x, done := mrf(); !done ) {
}

The use of the semicolon is, so to speak,
unambiguous.

Jonathan

Carlos Castillo

unread,
Sep 6, 2012, 2:20:53 AM9/6/12
to golan...@googlegroups.com
Go has goto, you could use that with the multi-section if-structure to make it obvious what's going on and avoid repetition: http://play.golang.org/p/mdS-6_B0Kf

Francesc Campoy Flores

unread,
Sep 6, 2012, 3:04:56 AM9/6/12
to Carlos Castillo, golan...@googlegroups.com
Using goto is ... well ... not a great idea in general :-)

It makes me think about http://en.wikipedia.org/wiki/Spaghetti_code

Even if that would work, I'd rather write this http://play.golang.org/p/bglgfHIDdN
--
--
Francesc

Andrew Gerrand

unread,
Sep 6, 2012, 3:35:23 AM9/6/12
to Francesc Campoy Flores, Carlos Castillo, golan...@googlegroups.com
On 6 September 2012 17:04, Francesc Campoy Flores <cam...@golang.org> wrote:
> Using goto is ... well ... not a great idea in general :-)

*cough*

http://golang.org/search?q=goto

Rob Pike

unread,
Sep 6, 2012, 10:39:34 AM9/6/12
to Andrew Gerrand, Francesc Campoy Flores, Carlos Castillo, golan...@googlegroups.com
As Ken famously said, if you need to go somewhere, a goto is the best way.

Goto is a tool. Use it when it's appropriate. Avoid it when it's not.
It's not often the right thing, but sometimes it is. As your search
shows, one place it's critical is the test program for the goto
statement.

-rob

N. Riesco - GMail account

unread,
Sep 6, 2012, 12:17:46 PM9/6/12
to golan...@googlegroups.com
Skimming through the search results, goto is used in the following cases:
I reckon the last two cases aren't really necessary, because the alternatives are more readable.


Nico

Carlos Castillo

unread,
Sep 6, 2012, 8:45:00 PM9/6/12
to golan...@googlegroups.com, Carlos Castillo
Although goto has had a history of being misused, resulting in more spagetti code than other control structures, in this situation I feel that the other solutions are harder to read, modify, and understand than my goto example.

Admittedly my first thought would be to do something like your suggestion, without the negative condition in the middle of the loop (http://play.golang.org/p/nhcmXiEmYc), even so, the goto solution IMHO is still easier to understand, and harder to make mistakes with when modifications are necessary.

Sometimes goto is the most appropriate solution to a problem, in this situation it allows you to turn a multi-clause if into a multi-clause while loop.

DisposaBoy

unread,
Sep 7, 2012, 9:22:42 AM9/7/12
to golan...@googlegroups.com
ate you sure? that labeled break looks to me like an infinite loop waiting to happen

Ian Lance Taylor

unread,
Sep 7, 2012, 9:51:06 AM9/7/12
to DisposaBoy, golan...@googlegroups.com
On Fri, Sep 7, 2012 at 6:22 AM, DisposaBoy <dispo...@dby.me> wrote:
> ate you sure? that labeled break looks to me like an infinite loop waiting to happen

A labeled break is not a goto statement. Or, rather, it is, but it
does not go to the label.

Ian

Larry Clapp

unread,
Sep 7, 2012, 9:53:06 AM9/7/12
to golan...@googlegroups.com
A break aborts the labeled loop, it doesn't break to the given label.


-- L
Reply all
Reply to author
Forward
0 new messages