golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.68k stars 17.49k forks source link

proposal: Go 2: For Else branch #41348

Closed snadrus closed 3 years ago

snadrus commented 3 years ago

Whenever a Golang program needs to determine a property of all of a set/list/map/chan, it requires an "if" branch operation on a "found" variable at the end of a loop. Ex:

var found bool
for _, v := haystack {
    if v == needle {
      found = true
      break
    }
}
if !found {  
  // Operation when the set lacks the item
}

With a For-Else construct, this could save a variable, a branch, 3 lines, and has good readability:

for _, v := range haystack {
   if v == needle {
      break
   }
} else {
  // Operation when the set lacks the item   
}

The assembly would be as simple as having break jump to a label below where the end of the For loop jumps to.

Go's overloaded For construct could allow this with Range and it can work with a condition. It has no interesting meaning for unconditional looping. This idea is borrowed from Python.

jcorbin commented 3 years ago

Fwiw, such a construct is possible today without the bool or resorting to assembly:


    for _, v := range haystack {
        if v == needle {
            goto next
        }
    }
    // Operation when the set lacks the item

next:
    // either way, we continue here

This sort of Pythonic for/else syntax would merely by sugar.

fzipp commented 3 years ago

Why not write a contains function, or wait for generics and write a generic contains function?

ianlancetaylor commented 3 years ago

For language change proposals, please fill out the template at https://go.googlesource.com/proposal/+/refs/heads/master/go2-language-changes.md .

When you are done, please reply to the issue with @gopherbot please remove label WaitingForInfo.

Thanks!

bcmills commented 3 years ago

Compare #24282

ltto commented 3 years ago

想你们这样 猫猫狗狗的需求都提到issues GO2会越来越臃肿的 现在也没有什么不好的啊

zigo101 commented 3 years ago

I often find I need the following else for form instead:

if len(values) == 0 {
   ... // print some info
} else for _, v := range values {
   ...
}

Surely, currently we can write it as

if len(values) == 0 {
   ... // print some info
}

for _, v := range values {
   ...
}

But I think the former is more logical (and could be a bit more efficient).

If if-block can follow else, why can't others?

[edit]: a better example for the occasion:

if vs := f(); len(vs) == 0 {
} else {
  for _, v := range vs {
  }
}

// vs.

if vs := f(); len(vs) == 0 {
} else for _, v := range vs {
}
deanveloper commented 3 years ago

I'm personally just not a fan of for else in python. It's very useful, but it just doesn't read well in my opinion and is often a bit confusing.

gopherbot commented 3 years ago

Timed out in state WaitingForInfo. Closing.

(I am just a bot, though. Please speak up if this is a mistake or you have the requested information.)

snadrus commented 3 years ago

For followers, the GOTO approach works: https://play.golang.org/p/8ha8Spl4vBG

So there's no need for "isFound" variables nor the setting or checking of them.

On Sun, Oct 11, 2020 at 3:17 PM GopherBot notifications@github.com wrote:

Closed #41348 https://github.com/golang/go/issues/41348.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/golang/go/issues/41348#event-3864000391, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOU4LTY3KHQJRTMAOMI5MTSKIAGBANCNFSM4RIBYJRA .

deanveloper commented 3 years ago

While that works in that specific example, the general case is a bit more complicated: https://play.golang.org/p/wMaykOGCfMC

The code requires 2 gotos which cross over each other, which can quickly lead to spaghetti code if there is more code in each section other than a simple fmt.Println. If code blocks and indents were used, it would look a lot better (which is the case for for-else). I however think that for-else doesn't look very good and isn't super intuitive. Maybe there is another word which could be used (fallthrough?), as the concept of for-else is very nice, however it just doesn't seem to lead to readable code. Maybe an entirely new concept could be thought up. Or we could just use a found variable for more complicated cases.

jcorbin commented 3 years ago

Maybe there is another word which could be used (fallthrough?)

notwithstanding

jcorbin commented 3 years ago

Looking back at this thread, I'm not sure if anyone's pointed out the precedent of text/template's {{ range }} ... {{ else }} ... {{ end }} ; so there it is fwiw