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: Go 2: introduce try/guard keyword for error handling #39890

Closed
andig opened this issue Jun 27, 2020 · 9 comments
Closed

proposal: Go 2: introduce try/guard keyword for error handling #39890

andig opened this issue Jun 27, 2020 · 9 comments
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

@andig
Copy link
Contributor

andig commented Jun 27, 2020

Go has suffered from seen a number of Go2 error handling proposals. I'm joining the chorus as I had the feeling that a comparatively less disruptive permutation of the discussion has not come up before. I'd be totally happy if this got closed right away, in that case sorry for wasting everybody's time.

Goals of this proposal:

  1. decrease verbosity, i.e. less typing and clearer structure of the non-error case
  2. full control over error handling, including annotating the error
  3. avoid hidden or non-local control flow magic

Before going to the details, I have considered:

Proposal

This is an adapted version of #33161 (comment), I couldn't find an original proposal to this case (/cc @carlmjohnson).

In short, I'm proposing to introduce a try keyword similar to Swift's guard that will be implemented as an error-checking and error-handling specific alternative to the existing if statement:

  • try must me followed by an assignment expression where the last assignment parameter must be an error and can be omitted
  • if the error parameter is omitted, a non-nil error (and other zero value or initialised variables) will be returned alongside with it. This does not require the error to be named in the API
  • if the try statement has a handler block, the block will be executed/ the error can be handled similar to if err != nil and returned or not. This typically requires the err parameter to be named.
  • unlike the if statement, a special scoping rule allows the assigned target variables (right term?) to escape the block (I understand this is similar to swift). This includes the error variable if it is named.

As such, this proposal is similar to #33161 (comment), taking the comments regarding control flow from #33161 (comment) into account.

Syntactically, the two following statements are equivalent:

try foo := bar()
try foo := bar() {
    return
}

It would look like

TryStmt = "try" AssignmentExpression [ Block ]

Examples

CopyFile

func CopyFile(src, dst string) error {
	try r := os.Open(src) // returns the error
	defer r.Close() // returns the error

	try w := os.Create(dst) // returns the error
	defer w.Close() // returns the error

	try io.Copy(w, r) // returns the error
	try w.Close() // returns the error
}

Update: Obviously this example needs an additional rule for error precedence during defer (tbd). Updated the defer Syntax. Using try inside deferred functions follows the same rules as everywhere else.

Hex

func main() {
	try hex, err := ioutil.ReadAll(os.Stdin) {
		log.Fatal(err)
	}

	try data := parseHexdump(string(hex)) {
		log.Fatal(err)
	}

	os.Stdout.Write(data)
}

Some thoughts

As @carlmjohnson said:

  • I think if something like this is done, it should be called guard because that's a name used by another language.
  • Probably it's not enough better than `if to be adopted.
@gopherbot gopherbot added this to the Proposal milestone Jun 27, 2020
@ianlancetaylor ianlancetaylor added error-handling Language & library change proposals that are about error handling. v2 A language change or incompatible library change LanguageChange labels Jun 27, 2020
@ianlancetaylor ianlancetaylor changed the title proposal: Go2: introduce try/guard keyword for error handling proposal: Go 2: introduce try/guard keyword for error handling Jun 27, 2020
@earthboundkid
Copy link
Contributor

earthboundkid commented Jun 28, 2020

What are the semantics of defer try w.Close()? Does it only assign an error if the existing error is non-nil? That would solve a real problem IMO.

I think the thing that really killed the last try proposal was that it made code coverage wrongly consider a try line “covered” even if it didn’t take the error path. Is there a way to handle that for try without a block in this proposal? Maybe auto-rewrite as a return block in coverage?

@andig
Copy link
Contributor Author

andig commented Jun 28, 2020

I think the thing that really killed the last try proposal was that it made code coverage wrongly consider a try line “covered” even if it didn’t take the error path.

@carlmjohnson could you link that proposal? Not sure which one you're referring to- I feel it's the one I couldn't find in my research?

@earthboundkid
Copy link
Contributor

#32437

@andig
Copy link
Contributor Author

andig commented Jul 7, 2020

What are the semantics of defer try w.Close()? Does it only assign an error if the existing error is non-nil? That would solve a real problem IMO.

@carlmjohnson removed that syntax as it obscured the flow of the error variable (and if ... defer is not legal either).

@simskij
Copy link

simskij commented Jul 7, 2020

I'm still not sure I get what adding some kind of try semantic to the language would solve that is not already addressed by if err != nil? One of the key strengths of go, in my opinion, is that it's strict and simple, without the unnecessary cognitive overhead introduced by offering multiple ways to solve the same problem.

@bitfield
Copy link

bitfield commented Jul 8, 2020

it's not enough better than if to be adopted

I think this is exactly right. It doesn't go far enough to satisfy the people who find writing if err != nil irritating, and it's entirely unnecessary for everybody else.

@andig
Copy link
Contributor Author

andig commented Jul 9, 2020

It doesn't go far enough to satisfy the people who find writing if err != nil irritating

I beg do disagree. I don't think you could reduce this much more unless sacrificing other aspects:

  • 1 line instead of three for the simple case
  • no need for err!=nil in the complex case
  • clear flow from code outline

... and it's entirely unnecessary for everybody else.

The number of error handling proposals, including those of go team members, shows that there is a wider need.

@simskij
Copy link

simskij commented Jul 9, 2020

The number of error handling proposals, including those of go team members, shows that there is a wider need.

At the same time, the fact that the proposals keep getting shot down indicates that the need so far has not outweighed the added complexity.

@andig
Copy link
Contributor Author

andig commented Jul 9, 2020

...absolutely. And since this one doesn‘t even develop traction in terms of comments or votes I‘m simply closing it to save everybody‘s time. Thanks for sharing your thoughts!

@andig andig closed this as completed Jul 9, 2020
@golang golang locked and limited conversation to collaborators Jul 9, 2021
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

6 participants