Go: proposal: Go 2: permit two clause for statement

Created on 13 Sep 2017  Â·  6Comments  Â·  Source: golang/go

I don't want to speak for other developers, but a very quick and dirty (yet effective) construct that I typically use for resilient code is the following retry pattern:

for {
  if err := try_something(); err == nil {
    break
  }
  fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
  time.Sleep(5 * time.Second)
}

For a brief moment, I thought I could brilliantly shorten this to the following:

for err := try_something; err != nil; {
  fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
  time.Sleep(5 * time.Second)
}

only to face palm myself about a minute later for neglecting the fundamentals of a for loop.

That being said, I believe that it would be a perfect addition to Go 2.0 (as this would be a language breaking change) to add support for such a construct by allowing the for loop to only contain a single semicolon, that is:

for err := try_something; err != nil {
  fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
  time.Sleep(5 * time.Second)
}

Where the first clause is executed before every iteration of the loop and the second is the condition that breaks if true, else executes the block.

Thoughts?

FrozenDueToAge Go2 LanguageChange Proposal

Most helpful comment

I don't think you need to make a langauge change here, just change how you
write your for loop

for err := try_something; err != nil; err = try_something { ... }

On Wed, 13 Sep 2017, 12:51 briansan notifications@github.com wrote:

I don't want to speak for other developers, but a very quick and dirty
(yet effective) pattern that typically use for resilient code is the
following retry pattern:

for {
if err := try_something(); err == nil {
break
}
fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
time.Sleep(5 * time.Second)
}

For a brief moment, I thought I could brilliantly shorten this to the
following:

for err := try_something; err != nil; {
fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
time.Sleep(5 * time.Second)
}

only to face palm myself about a minute later for neglecting the
fundamentals of a for loop.

That being said, I believe that it would be a perfect addition to Go 2.0
(as this would be a language breaking change) to add support for such usage
by allowing the for loop to only contain a single semicolon, that is:

for err := try_something; err != nil {
fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
time.Sleep(5 * time.Second)
}

Where the first clause would be executed before every iteration of the
loop and the second would be the condition that would break if true, else
execute the block.

Thoughts?

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/golang/go/issues/21855, or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAcA9VAM1ghoEjIbAVX6IXprh07_xOaks5sh0MwgaJpZM4PVgor
.

All 6 comments

I don't think you need to make a langauge change here, just change how you
write your for loop

for err := try_something; err != nil; err = try_something { ... }

On Wed, 13 Sep 2017, 12:51 briansan notifications@github.com wrote:

I don't want to speak for other developers, but a very quick and dirty
(yet effective) pattern that typically use for resilient code is the
following retry pattern:

for {
if err := try_something(); err == nil {
break
}
fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
time.Sleep(5 * time.Second)
}

For a brief moment, I thought I could brilliantly shorten this to the
following:

for err := try_something; err != nil; {
fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
time.Sleep(5 * time.Second)
}

only to face palm myself about a minute later for neglecting the
fundamentals of a for loop.

That being said, I believe that it would be a perfect addition to Go 2.0
(as this would be a language breaking change) to add support for such usage
by allowing the for loop to only contain a single semicolon, that is:

for err := try_something; err != nil {
fmt.Println("something went wrong, trying again in 5s", "err", err.Error())
time.Sleep(5 * time.Second)
}

Where the first clause would be executed before every iteration of the
loop and the second would be the condition that would break if true, else
execute the block.

Thoughts?

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/golang/go/issues/21855, or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAcA9VAM1ghoEjIbAVX6IXprh07_xOaks5sh0MwgaJpZM4PVgor
.

This sounds like a library rather than a language change. Even then there are many ways that retries can be done. Is the retry delay the same, is it an exponential backoff, is it geometric? How many times does it retry before giving up?

Even if it were a library, why does it have to be in the standard library?

I think the basic proposal here is to change the for statement to add a two-clause variant, in which the initialization statement is executed each time around the loop.

We've considered this in the past and rejected it because it means that the presence or absence of a semicolon, which can be rather subtle, makes a big difference to the program. For example, currently

for f() { ... }

executes while f() returns true. With this change one might accidentally write

for f(); { ... }

which looks quite similar but is in fact an infinite loop that executes a each time around the loop.

This is not to say that we should not consider this again. I just want to explain why we have rejected the idea in the past.

Requiring content in both clauses would avoid the subtle trap @ianlancetaylor mentions.

for f(); { ... } // compilation error: second clause must not be empty

There is a second subtlety, however, which could not be as easily avoided:

for err := f(); err != nil {
  // f() executes before each iteration.
}

for err := f(); err != nil; {
  // f() executes only once.
}

Thank you for all the feedback; I do agree with your points that there are nuances to this feature that could potentially cause more problems than solve. Feel free to close

As Ian said, we discussed this in the past and decided it was too dangerous.

Was this page helpful?
0 / 5 - 0 ratings