Go's proposed try()
will be used and that will change how code is written
One of the recent commotions in Go is over the Go team's proposed
try()
built-in error check function,
which is currently planned to be part of Go 1.14 (cf). To simplify, 'a, [...] :=
try(f(...))
' can be used to replace what you would today have to
write as:
a, [...], err := f(...) if err != nil { return [...], err }
Using try()
means you can drop that standard if
block and
makes your function clearer; much more of the code that remains
is relevant and important.
Try()
is attractive and will definitely be used in Go code,
probably widely, and especially by people who are new to Go and
writing more casual code. However, this widespread use of try()
is going to change how Go code is written.
One of my firm beliefs is that most programmers are strongly driven
to do what their languages make easy, and I don't think try()
is
any exception (I had similar thoughts about the original error
handling proposal). What try()
does is
that try()
makes returning an unchanged error the easiest thing
to do. You can wrap the error from f()
with more context if you
work harder, but the easiest path is to not wrap it at all. This
is a significant change from the current state of Go, where wrapping
an error is a very easy thing that needs almost no change to the
boilerplate code:
a, [...], err := f(...) if err != nil { return [...], fmt.Errorf("....", ..., err) }
In a try()
world, adding that error wrapping means adding those
three lines of near boilerplate back in. As a result, I think that
once try()
is introduced, Go code will see a significantly increased
use of errors being returned unchanged and unwrapped from deep in
the call stack. Sure, it's not perfect, but programmers are very
good at convincing themselves that it's good enough. I'm sure that
I'll do it myself.
This change isn't necessarily bad by itself, but it does directly
push against the Go team's efforts to put more context into error
values, an effort that actually landed changes in the forthcoming
Go 1.13
(see also the draft design).
It's possible to combine try()
and better errors in clever ways,
as shown by How to use 'try', but it's not the
obvious, easy path, and I don't think it's going to be a common way
to use try()
.
I am neither for or against try()
at the moment, because I think that
being for or against it in isolation is asking the wrong question. The
important question is how Go wants errors to work, and right now the Go
team does not seem to have made up its mind. If the Go team decides
that errors should frequently be wrapped on their way up the call stack,
I believe that try()
in its current form is a bad idea.
(If the Go team thinks that they can have both try()
in its current
form and people routinely wrapping errors, I think that they are
fooling themselves. try()
will be used in the easiest way to use it,
because that's what people do.)
PS: While Go culture is currently relatively in favour of wrapping
errors with additional information, I don't think that this culture
will survive the temptation of try()
. You can't persuade people
to regularly do things the hard way for very long.
Update: The Go team dropped the try()
proposal due
to community objections, rendering the issue moot.
Comments on this page:
|
|