-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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: support "assign if nil" statement to tackle error handling boilerplate #21732
Comments
|
@cznic Yeah, it conflicts with the current syntax. There are a few ways to get around that:
|
As I mentioned over on #21161, I personally would prefer to see any change to error handling make it just as easy to wrap an individual error with more information as it does to simply move the error along. |
@ianlancetaylor As you can see in the proposal, the error is wrapped with contextual information at the end. d, (err) := f3(b, c)
if err != nil {
return nil, errors.Wrap(err, "failed")
} Functions that return errors should (and usually do) provide contextual informatiom themselves. Therefore you don't need to return "failed on pkg.Func" because that info is provided by the error returned from When higher contextual information granularity is needed, one just falls back to the old style. But, I think that in such cases it doesn't feel like a boilerplate, because you're doing different things with each error. |
It would be nice if someone gave this a Go2 label. |
what if we add a ? in the error variable
and this is like if we had this code
This solution es pretty similar to the one that rust uses for error handling https://m4rw3r.github.io/rust-questionmark-operator |
@mrkaspa I like the question mark as a replacement for the parenthesis. So I would write this: a, b, err? := f1()
c, err? := f2(a)
d, err? := f3(b, c)
if err != nil {
return nil, errors.Wrap(err, "failed")
} That's pretty nice, probably even nicer than my original proposal. However, I don't think that automatically returning on |
@faiface I think it is, because this is the problem that godevs have when the handle they need to do is to return the error, if they need to handle this in another way they can use only err and handle it with a custom if |
I think the question mark is generally used with null/nil. |
What about if when I do this: a, b, err? := f1() expands to this: if err != nil {
return nil, errors.Wrap(err, "failed")
} and I can force it to panic with this: a, b, err! := f1() expands to this: if err != nil {
panic(errors.Wrap(err, "failed"))
} This will keep backward compatibility, and will mend all the pain points of error handling in go |
@SCKelemen in those languages the ? goes on the type not in the variable |
@mrkaspa
Just to clarify, my proposal is to simply skip the assignments where variables marked with |
Just to check my understanding, given this code: var errF1 = errors.New("f1 error")
func f1() (string, error) {
return "f1", errF1
}
func f3() {
fmt.Println("f3")
}
// f2(), f4() purposely left out, they're implementations aren't important.
func run() error {
_, (err) := f1()
_, (err) := f2()
f3() // f3() is always executed?
_, (err) := f4()
return err
}
|
@buchanae That's right! |
@faiface Since go does not have a ternary operator, what about this:
which could obviously be extended to
The docs would be as clear as: "The ternary operator in go differs from that in C in that the condition is a single variable which is implicitly checked for being a zero value". |
Issue #21161 is a general discussion of error handling changes to the languages. Closing this issue in favor of that one. |
Hello,
it seems to me that when people complain about Go's error handling, they mostly complain about the situations when it gets repetitive (otherwise I assume it's not a big problem), like this:
Now, I usually don't encounter code like this, but I agree that this looks awful and is hard to prevent sometimes.
So I came up with a simple solution. Keep in mind, the solution is just an idea which might be iterated upon, or completely thrown away.
Assign if nil statement
Here's my solution.
In an assignment statement (
=
or:=
), when any LHS operand is surrounded by parenthesis, the assignment will evaluate and assign if and only if all parenthesis-surrounded LHS operands are zero value (nil or an appropriate equivalent)In case of
:=
assignment, variables undeclared before are treated as zero valued.What I mean is basically that this
gets translated to this
In general, something like this
gets translated to
How does this help?
With "assign if nil" statement, we can rewrite the original error handling chain like this:
In the first line,
err
is undeclared and thus is handled as if it wasnil
andf1
executes. Next line only executesf2
and assigns the values iferr
is still nil, i.e. when the previous call finished without errors. The same holds for the third line.In the last line, we nicely wrap the error with additional context information and return it.
Other uses
There are more uses of the "assign if nil" statement. For example, lazily initializing a map:
Summary
I propose introducing an "assign if nil" statement. Proper formal specification is not done here, but is easy to imagine.
I think this construct solves most of the hassle with error handling in Go. An
if err != nil
once a while is perfectly fine, the only problem is when there is too many of them. I believe that's almost always possible to avoid using this construct.Looking forward to your feedback!
Michal Štrba
The text was updated successfully, but these errors were encountered: