Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: spec: else statement in assign statements #56895

Closed
protiumx opened this issue Nov 22, 2022 · 1 comment
Closed

proposal: spec: else statement in assign statements #56895

protiumx opened this issue Nov 22, 2022 · 1 comment
Labels
error-handling Language & library change proposals that are about error handling. FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Milestone

Comments

@protiumx
Copy link

Author background

  • 1 year experience writing production Go code.
  • Other language experience: Python, Typescritpt, Rust, C#.

Related proposals

This proposal is about else statements in assign statements. It is exclusively borrowed from the let-else statement introduced in Rust RFC 3137, which is also based on Swift's guard statement.

I haven't been able to find a similar existing proposals. Please close if duplicated.

Proposal

The goal of this proposal is to introduce a guard to simplify some very common error-handling patterns we frequently encounter when writing Go code. A short-hand way to return errors has been proposed a few times already (See #56628, #32437, #56165). I believe the existing proposals don't match 100% Go's mission for simplicity, correctness and readability.

Although introducing this feature could go against R. Pike's comment Go does not try to be like the other languages (See https://go.dev/talks/2015/simplicity-is-complicated.slide#9) I think the benefit is hard to ignore.

Code examples:

// before
result, err := getUser()
if err != nil {
  return err
}

exp, ok := number.(uint64)
if !ok {
  return fmt.Errorf("not uint64")
}

// after
result, err := getUser() else {
  return err
}

exp, _ := number.(uint64) else {
  return fmt.Errorf("not uint64")
}

The new else statement in a variable statement is easy to read and understand. It allows the developer to write code and think of its immediate error handling by moving the failure case into the body of the assign expression itself.

Spec

Only the last value is evaluated as the else condition. The last value must implement the error interface or be type bool

ret1, ret2, err := test() else {
  return err
}

ret1, err1, err2 := test() else {
  // err2 is not nil
  return err2
}

func testA() (error, string)


err, s := testA() else { // Compilation error. `s` does not implement `error` interface
  return err
}

Variable scope works as expected. Variables are not scoped to the else block

ret, err := testA() else {
  return err
}

// reuse err
ret2, err := testB() else {
  return err
}
err = testC() else {
  return err
}

Only available in assign statements

// Invalid: no assign statement
testC() else {
  return err
}

Only valid for a single expression on the right hand of the assignment

a, b := testA(), testB() else { // invalid
...
}

It is possible to omit the last returned value in type assertions and map access (as it is already possible)

exp := number.(uint64) else {
  return fmt.Errorf("not uint64")
}

m := map[string]string{}
value := m["value"] else {
  return fmt.Errorf("value not found")
}

Motivation

Go's simplicity is great but that simplicity usually come with a cost of repetition, especially when talking about error handling.
Go does not support pointer to boolean conversion hence developers have to write the following block constantly

ret, err := some()
if err != nil {
  return err
}

Although, this can be easily solved with a code snippet, codebases tend to be saturated by

if err != nil {
  return err
}

statements.
The proposal avoids repetition of the if err != nil code. There is no nil to bool conversion as the else statement would internally evaluate err != nil as its condition.

Readability is maintained or improved if considered that error handling is now part of the assignment statement.

Please refer to Rust RFC 3137 for more details on its motivation as I believe Go developers would agree with them.

Compatibility

Old code will continue to compile on newer versions of Go.
New code will not compile on older versions of Go unless this feature is back-ported to older releases or automated tooling will desugar it.

Costs

What is the cost of this proposal?

An additional rule to understand when assigning variables. Specifically the rule of evaluating only the last result returned by the right hand of the assign statement.

Would this change make Go easier or harder to learn, and why?

Go is already a very simple language to learn. The intention of this new assign expression could seem natural to understand.
The new expression is also intended to be optional and more of a syntax sugar.

How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?

Linters and formatters would require to be extended to support the new assign expression.

What is the compile time cost?

Probably none. Some compilation step could be affected but it depends on the implementation. A naive approach could imply a desugar step of the source code. Otherwise the cost would reside during parsing step, modification to the AssignStmt in Go's AST or a new type of expression would be required.

What is the run time cost?

None

Can you describe a possible implementation?

I imagine extending the AssingStmt with an Else statement field (similar to Else in IfStmt).
The evaluation of this Else statement should work as expected when finding a return statement.

@gopherbot gopherbot added this to the Proposal milestone Nov 22, 2022
@seankhliao seankhliao added LanguageChange v2 A language change or incompatible library change error-handling Language & library change proposals that are about error handling. labels Nov 22, 2022
@seankhliao
Copy link
Member

Duplicate of #41908

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
error-handling Language & library change proposals that are about error handling. FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

3 participants