2018-12-16
The Go 2 Error Handling proposal will likely lead to more use of error
in return types
One of the bits of the Go 2 error handling proposal
that some people dislike is that the new check
keyword only works
on values of type error
. I've seen a number of suggestions in
the wiki feedback page that
widen this, making check
more generally applicable. I don't have
a strong opinion on this, but I do have an observation on the current
approach.
One of my firm beliefs is that most programmers are strongly driven to do what their languages make easy. If a language makes something the easiest path to what programmers want, programmers will use that path, even if it's not what the path is really for and even if it requires some contortions. What the language designers feel about this or advocate doesn't really matter; people will not take the hard road just because you want them to and think they should.
In the current Go 2 error handling proposal, using a check
on an
error
value is the easiest way to check for exceptional conditions.
The obvious thing to expect here is that people will increasingly
signal exceptional conditions through error
values, including
adding them to APIs where necessary or changing return values from
other types (especially bool
) to error
instead. The resulting
error
may or may not be meaningful (in some cases it will be a
boolean), but it can be used with check
to make exception handling
easy, and that's what a lot of people will care about.
(Some of these APIs will be public, but a lot more will be internal or even the informal 'APIs' of internal functions and methods inside a package.)
Whether or not this is a good thing probably depends on your
perspective. On the one hand, we're likely to see a lot more use
of error
rather than people making up their own error mechanisms.
On the other hand, some of those uses of error
will not be for
actual errors and the error
values won't be particularly meaningful.
Some of them will really be booleans, where the only thing that
matters is whether the value is nil
or non-nil
. This risks
confusing other people who expect the error
values to have any
meaning or use beyond the nil
check used by check
.
If people consider this change in error
usage to be a bad thing,
I don't think that there's any way out short of either not implementing
error handling or of making check
more general somehow.
(This is related to my views on the Go 2 error inspection proposal, where I also expect people to do what the proposal makes easiest, whether or not it's what the language designers want.)
Sidebar: A reason to keep check
restricted to error
values despite this
An error
value is a clear signal that this is where you find
whether or not something has succeeded (well, mostly, and CGo is
an exception that is not really in normal Go APIs).
This means that you can be very confident that checking an error
for non-nil is a proper activity; you are not accidentally checking
something that is not really an error signal. You can't have as
much confidence in bool
values or the like, and therefor there's
a higher chance that programmers who are slapping check
in front
of functions that return bool
are actually making a (tempting)
mistake.
You might think that no one would ever make this sort of confusion. I disagree; exactly what is and isn't an error, and how they're signaled, is something that can easily go wrong if you're not working with something that is completely unambiguous. See, for example, how ZFS on Linux accidentally misunderstood an error return in a way that caused a kernel crash.
(In Go, a non-nil
error
value meaning an error is socially
unambiguous, and it would become more so in a world with check
in it. CGo is an unfortunate forced exception that I don't think
anyone likes.)