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: error handling with orbail err #67955

Closed
xmonader opened this issue Jun 12, 2024 · 21 comments
Closed

proposal: spec: error handling with orbail err #67955

xmonader opened this issue Jun 12, 2024 · 21 comments
Labels
error-handling Language & library change proposals that are about error handling. LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal Proposal-FinalCommentPeriod
Milestone

Comments

@xmonader
Copy link

xmonader commented Jun 12, 2024

Proposal for Error Handling in Go using the orbail Syntax

Introduction

Error handling is a critical aspect of software development, especially in a language like Go where explicit error handling is a core principle. This proposal introduces a small addition to the language, orbail, which aims to streamline and simplify error handling in Go code. The orbail keyword can be used to handle errors in a more concise and readable manner, potentially reducing boilerplate code and enhancing code clarity.

orbail is coming from or bail, it can be also any other suitable token

Concept

The orbail syntax allows developers to chain error checks directly within expressions. When an error occurs, orbail immediately handles it
This concept is inspired by the or die syntax in Perl and PHP, which allows for immediate error handling in a concise manner. Similarly, orbail (or its alternatives such as orelse or orfail or orreturn utilizing the || operator) aims to provide a flexible and developer-friendly approach to error handling in Go. This change is totally opt-in, and also won't break existing code.

Strategy

Optimize for the common cases that add visual noise to the code and cause the frustration which are

val, err := func()
if err != nil {
	return err
}

or

val, err := func()
if err != nil {
	return fmt.Errorf("some error %w", err)
}

Suggestion 1: The user specifies all of the returns (explicit )

The user bails with return values

txt, err := http.Get() orbail "", error.Errorf("some error %w", err)

Which I believe is more aligned with go's philosophy and simpler for the compiler implementation

Example : wrapping an error

Before

func getData() (string, error) {
	txt, err := http.Get()
	if err != nil {
		return "", fmt.Errorf("some error %w", err)
	}
	...
	return txtProcessed, nil
}

After:

func getData() (string, error) {
	txt, err := http.Get() orbail "", fmt.Errorf("some error %w", err)
	...
	return txtProcessed, nil
}

Suggestion 2: the user only specifies the error (implicit)

Coming from the name the user only care about failing or bailing with a specific error, so here a more implicit suggestion around specifying the errors only, which there is a consensus on having the error as the last return value of the function

Case 1: Implicit return

In its simplest form, orbail can handle errors immediately:

txt, err := http.Get() orbail

If http.Get() returns an error, orbail will do an implicit return with zero values for all of the arguments, but the last one (the error) is returned implicitly

Case 2: Wrapping an error

You can also return a wrapped error if needed:

txt, err := http.Get() orbail error.Errorf("some error %w", err)

Example 1: Basic Error Handling

Before:

func getData() (string, error) {
	txt, err := http.Get()
	if err != nil {
		return "", err
	}
	...
	return txtProcessed, nil
}

After:

func getData() (string, error) {
	txt, err := http.Get() orbail
	...
	return txtProcessed, nil
}

Example 2: Custom Error Message

Before:

func getData() (string, error) {
	txt, err := http.Get()
	if err != nil {
		return "", fmt.Errorf("some error %w", err)
	}
	...
	return txtProcessed, nil
}

After:

func getData() (string, error) {
	txt, err := http.Get() orbail fmt.Errorf("some error %w", err)
	...
	return txtProcessed, nil
}

Personal Opinions

  • I do not prefer to use || given in the implicit case of orbail or orfail as it will look very weird and will not communicate the intention
  • I prefer to use orbail or orfail as it communicates the intention better than orelse
  • This proposal only allows none or a single error Expression after the orbail (in case of the implicit) or a single return expression in the case of the implicit.
  • the moment you need to add a new block, I believe you should switch back to the classical error handling.

Benefits

  • Conciseness: Reduces repetitive error handling code.
  • Readability: Makes error handling logic more readable and easier to follow.
  • Flexibility: Allows custom error messages and handling strategies.
  • Covers most of main scenarios of error handling in Go.

Implementation Details

To implement this syntax, the Go compiler would need to be extended to recognize and process the orbail keyword (or its alternatives). The following steps outline a high-level approach to the implementation:

  • Parsing: Extend the Go parser to recognize orbail, orelse as valid tokens. (we can also reuse the else keyword to be else or else return or orelse return
  • Immediate rewrite to if err!=nil block: Replace orbail with if err!=nil

Conclusion

The proposed orbail syntax offers a streamlined and flexible approach to common scenarios in error handling in Go, reducing boilerplate code and improving readability. By allowing developers to handle errors directly with less typing it simplifies the coding process and enhances the overall developer experience

@gabyhelp
Copy link

Similar Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@ianlancetaylor ianlancetaylor added LanguageChange Suggested changes to the Go language v2 An incompatible library change error-handling Language & library change proposals that are about error handling. labels Jun 12, 2024
@ianlancetaylor
Copy link
Member

More or less a duplicate of #21161 or #61750.

@xmonader
Copy link
Author

xmonader commented Jun 12, 2024

@ianlancetaylor yes, thanks for linking these, I believe it's different because it only optimizes for the common cases, and doesn't allow having more scopes or blocks. Just a single error or implicit orbail with no arguments

@apparentlymart
Copy link

It took me longer than I'd like to admit to realize that I was supposed to read orbail as "or bail", rather than "orb ail" or a single word "orbail" (whatever those would mean). 😖

The use of "bail" as in "bail out" to mean "return early with an error" seems unusually casual and "slang-ish" compared to the rest of the language.

I've heard on numerous occasions that words run together all in lower-case can be particularly hard to parse for those who have less experience with the English language, because they don't have as much vocabulary readily available to draw on when guessing where the word boundaries might be. I am a native English speaker who frequently encounters run-together words like this but yet I also struggled with this one, I think in large part because the verb "bail" is not a word I expected to encounter in this context. I think the use of a somewhat-ideosyncratic word and running it together with another word with no delimiters makes this case particularly tricky, but I'm curious to learn if I'm the outlier here.

Aside from the keyword name I don't think I have any particularly strong reaction to this proposal either positive or negative. I wouldn't be upset if it were added to the language using a different word or symbol. However, it does seem like all of the other similar proposals were already rejected and I don't see any significant differences aside from the specific choice of keyword. 🤔

@ruyi789
Copy link

ruyi789 commented Jun 13, 2024

It doesn't look comfortable, you'll be guessing what value he's returning instead of confirming his return value. And modifying it to if requires truncating a line.

@justinfx
Copy link

Would it be a compilation error if you tried to use orbail within a function where the last return value is not an error?

@raff
Copy link

raff commented Jun 13, 2024

  • Does this implementation expects that the called function always return the error as last parameter ?
  • Does this implementation expects that the calling function always return an error and always as last parameter ?
    I am assuming the answer is yes in both cases but your proposal doesn't specify it.

@xmonader
Copy link
Author

It took me longer than I'd like to admit to realize that I was supposed to read orbail as "or bail", rather than "orb ail" or a single word "orbail" (whatever those would mean). 😖

The use of "bail" as in "bail out" to mean "return early with an error" seems unusually casual and "slang-ish" compared to the rest of the language.

I've heard on numerous occasions that words run together all in lower-case can be particularly hard to parse for those who have less experience with the English language, because they don't have as much vocabulary readily available to draw on when guessing where the word boundaries might be. I am a native English speaker who frequently encounters run-together words like this but yet I also struggled with this one, I think in large part because the verb "bail" is not a word I expected to encounter in this context. I think the use of a somewhat-ideosyncratic word and running it together with another word with no delimiters makes this case particularly tricky, but I'm curious to learn if I'm the outlier here.

Aside from the keyword name I don't think I have any particularly strong reaction to this proposal either positive or negative. I wouldn't be upset if it were added to the language using a different word or symbol. However, it does seem like all of the other similar proposals were already rejected and I don't see any significant differences aside from the specific choice of keyword. 🤔

Hi! Thanks for taking the time. Definitely not an outlier. I agree maybe orbail isn't the most suitable keyword, I added couple of other suggestions like orfail, orelse, else return.

@xmonader
Copy link
Author

It doesn't look comfortable, you'll be guessing what value he's returning instead of confirming his return value. And modifying it to if requires truncating a line.

Thanks for taking the time! Yes, 100% correct there is some sort of implicitness comes with bailing out which is specifying the error only and default the rest to zero value. I added a more explicit version where the user specifies all of the returns, and I would love to know what you think!

@xmonader
Copy link
Author

Would it be a compilation error if you tried to use orbail within a function where the last return value is not an error?

Should be, yes. The compiler will need to check the return arguments as if it was the wrong return statement

I added a more explicit version too where the user specifies all of the returns in his bail as well

@xmonader
Copy link
Author

  • Does this implementation expects that the called function always return the error as last parameter ?

Yes, in the implicit suggestion it assumes the last return would be an error

  • Does this implementation expects that the calling function always return an error and always as last parameter ?

Yes

I am assuming the answer is yes in both cases but your proposal doesn't specify it.

Thanks for pointing that out!
I added also a more explicit suggestion for orbail and would love to hear your take on that

@ruyi789
Copy link

ruyi789 commented Jun 13, 2024

Code without an if is never good code, so be honest and use an if. err-handle is a fancy feature that only does what it is supposed to do by default, and there's no way to place breakpoints.

@xmonader
Copy link
Author

Code without an if is never good code, so be honest and use an if. err-handle is a fancy feature that only does what it is supposed to do by default, and there's no way to place breakpoints.

This proposal is only for err handling by immediately returning the error to the caller(implicitly or explicitly). If the user wants to do more than that it explicitly mentions to use the if err check.

For the breakpoint, It only allows one expression, the arguments for return - I'm talking about the explicit suggestion 1-

@muhamadazmy
Copy link

muhamadazmy commented Jun 13, 2024

In general, I like the idea of having a quick handling of errors when you only need to return the error. So you don't have to explicitly check if err != nil just to return the error (with or without a context).

But I have few suggestions on the proposal:

On orbail statement, should never return an err when called like this

func mightFail() (string, error) {
  ...
}

func caller() error {
   result := mightFail() orbail 
}

onbail should always expose the captured error to its capture statement, say we call it failure which becomes a keyword only inside the onbail statement

func caller() error {
   result := mightFail() orbail fmt.Errorf("something went wrong: %w", failure)
}

@xiaokentrl
Copy link

这看起来不舒服,你会猜测他返回的价值,而不是确认他的回报价值。将其修改为 if 需要截断一行。

If you are Shakyamuni, you would help anyone in difficulty. If you position yourself as a noble person, you will go and solve the difficulties that people need help with.

@gopherbot gopherbot added this to the Proposal milestone Jun 17, 2024
@bronger
Copy link

bronger commented Jun 24, 2024

Slightly OT: Again, an else return occurrence. I’ve been wondering to add just that? I like it a lot … easy to explain, no new keyword, all exit points are sill marked with return, … Of course, wrapping errors still had to use the old way. But it simplifies a frequent case nevertheless.

txt, err := http.Get() else return

Error handling proposals that cover wrapping perpetually become too complicated. And, I don’t think that it is agreed upon in the Go community that wrapping is always a good idea in the first place, especially within a library.

Does it make sense to write a proposal?

@seankhliao seankhliao changed the title proposal: Proposal for Error Handling in Go using the orbail Syntax proposal: Go 2: error handling with orbail err Jun 24, 2024
@ianlancetaylor
Copy link
Member

@bronger Sounds like #56895 or #65793.

@bronger
Copy link

bronger commented Jun 24, 2024

The USP would be that – given that more complex proposals are notoriously rejected – one would propose a construct without any parameters.

@ianlancetaylor
Copy link
Member

I really don't want to encourage anybody to write any more error handling proposals that are minor variations on existing ones. We just wind up making the same points over and over.

    txt, err := http.Get() else return

Here are some questions I have that I've written for dozens of earlier proposals. My goal is not to tweak this proposal to answer these questions. It's to point out that we've seen and rejected a lot of error handling proposals.

  1. Nowhere else in Go does a statement like return appear without being enclosed in curly braces.
  2. Presumably this will return if err != nil. So why are we writing err at all? Just seems like boilerplate.
  3. Wrapping does matter, and it's a mark against an error handling proposal if it doesn't support it.
  4. What if the function has multiple results?

@bronger
Copy link

bronger commented Jun 24, 2024

(2) and (4) are addressed in in this issue.

However, I am grateful for your point (3). Then, I refrain from it.

@ianlancetaylor ianlancetaylor changed the title proposal: Go 2: error handling with orbail err proposal: spec: error handling with orbail err Aug 6, 2024
@ianlancetaylor ianlancetaylor added LanguageChangeReview Discussed by language change review committee and removed v2 An incompatible library change labels Aug 6, 2024
@ianlancetaylor
Copy link
Member

This syntax is unlike anything else in Go, with an implicit return and no curly braces around a block. The proposal is very similar to #61750, which uses orelse with only a minor syntax variation (adding return). It's not clear why err is still defined on the left hand side. The emoji voting is not in favor. Therefore, this is a likely decline. Leaving open for four weeks for final comments.

@ianlancetaylor
Copy link
Member

No further comments.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
error-handling Language & library change proposals that are about error handling. LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal Proposal-FinalCommentPeriod
Projects
None yet
Development

No branches or pull requests