go: proposal: Go 2: introduce "then" keyword in if statement to allow one liner if statement for better error handling.

Would you consider yourself a novice, intermediate, or experienced Go programmer? Experienced

What other languages do you have experience with? C, C++, Javascript, Java, Python, Delphi, Rust

Would this change make Go easier or harder to learn, and why? I don’t think it makes the GO harder to learn. The proposed “then” keyword allows the one line if statement

Has this idea, or one like it, been proposed before? The solution is similar with the most other error handling proposals. This proposal doesn’t add any other code changes

If so, how does this proposal differ?

Who does this proposal help, and why? 1. It helps authors of Go source code avoid three extra lines of code in the common case where they early exit on an error. 2. It helps readers of Go source code follow a function’s core logic more easily, by collapsing the gap between two successive lines of logic. 3. Preserves the imperative style of Go source code. Unlike the try proposal, this proposal can’t be abused to favor function composition.

What is the proposed change? 1. A new keyword “then” for the if statement is introduced. 2. The keyword is only valid in if statements on the right-hand-side of the if statement allowing one line if statements. 3. After the keyword a statement is required but it can be a block as well. 5. In all other cases, check is a normal identifier. This keeps the change backwards-compatible to Go1. 6. Given a function like this:

func foo() (v1 T, err error) {
  var x T
  if x,  err = f(); err != nil then return
}
is equivalent to the following code:

func foo() (v1 T, err error) {
  var x T
  if x, err = f(); err != nil {
    return nil, err
  }
}

Is this change backward compatible? Yes. Totally!

Show example code before and after the change. Before https://play.golang.org/p/bQeCE9zzDPa

func printSum(a, b string) (err error) {
        var x,y int
	if x, err = strconv.Atoi(a); err != nil {
		return
	}
	if y, err = strconv.Atoi(b); err != nil {
		return
	}
	fmt.Println("result:", x + y)
	return nil
}

After using the “then” keyword

func printSum(a, b string) (err error) {
        var x,y int
	if x, err = strconv.Atoi(a); err != nil then return
	if y, err = strconv.Atoi(b); err != nil then return
	fmt.Println("result:", x + y)
	return nil
}

What is the cost of this proposal? (Every language change has a cost). None. Just a regex parse.

How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected? I guess it requires only one regex expression.

What is the compile time cost? Time-complexity-wise the same. Can be implemented entirely in the frontend.

What is the run time cost? Nothing

Can you describe a possible implementation? It is just another regex in the language parser

Does this affect error handling? Yes

We are working on a go project. We have about 18,000 LOC. about 18% of the LOC are just error handling… Error handling in GO is a nightmare because of the required brackets and code format.

It can also be handy in other parts of the code

func (wallet *Wallet) loadWallet() error {

   if _, err := os.Stat("wallet.txt") ; err == nil {
        if err := wallet.read(); err != nil { 
           return err 
       }
        if wallet.encrypted {
           if err := wallet.decrypt(); err != nil {
             return err
          }
       } 

   } else {
       if err := wallet.createAddress(); err != nil then return err
   }

   if wallet.addresses == 0 {
         errors.new("There are no addresses in the wallet")
   }
   return nil
}
func (wallet *Wallet) loadWallet() error {

   if _, err := os.Stat("wallet.txt") ; err == nil {
        if err := wallet.read(); err != nil then return err
        if wallet.encrypted then
           if err := wallet.decrypt(); err != nil then return err     
   } else then
       if err := wallet.createAddress(); err != nil then return err

   if wallet.addresses == 0 return errors.new("There are no addresses in the wallet")

   return nil
}

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 39
  • Comments: 23 (8 by maintainers)

Most upvoted comments

What if we fixed go fmt so you could write

if x, err = strconv.Atoi(a); err != nil { return }

It’s two characters shorter than than, if that’s important.

Right, but if we’re talking bout chasing the language, something on the table for comparison should be changing go fmt to permit trivial if blocks to stay on the same line.

Maybe change gofmt to allow following to stay on the same line:

if err != nil {{ return }}

Or when there is a comment:

if err != nil { return } //gofmt:inline

Based on the discussion above, and the emoji voting, this is a likely decline. Leaving open for four weeks for final comments.

I don’t know how to disable gofmt in goland. If you tell me then I will disable it and I will never activate gofmt again. I only see that you guys received over 50+ proposals in all these years for different one liner error handling and all of them were refused for one reason or another.

To illustrate why gofmt is bad in practice… Just a random thing I was working on right now… and the reason why a real world one liner if statement and error handling is really useful.

select {
case newWork, ok := <-continueProcessingCn:
	if !ok {
		return
	}
	if newWork != nil {
		work = newWork
		listIndex = 0
		txMap = make(map[string]bool)
	}
case _, ok := <-suspendProcessingCn:
	if !ok {
		return
	}
	continue
}
if work == nil {
	continue
}
if len(txList) > 1 {
	sortTxs(txList)
}
select{
case newWork, ok := <- continueProcessingCn:
	if !ok then return
	if newWork != nil {
		work = newWork
		listIndex = 0
		txMap = make(map[string]bool)
	}
}
case _, ok := <- suspendProcessingCn:
	if !ok then return
	continue
}
if work == nil then continue
if len(txList) > 1 then sortTxs(txList)

22 LOC vs 15 LOC. A reduction of 31.81% LOC