📜 ⬆️ ⬇️

Why “errors are meanings” in Go

Recently, I translated a great article by Rob Pike “Errors is values” , which was not properly assessed at Habré. This is not surprising, since it was posted on the official Go blog and is designed for Go programmers. However, the essence of the article is not always immediately obvious to experienced programmers. And yet, I think its message is key to understanding the approach to error handling in Go, so I will try to explain it in my own words.

I remember well my first impression from reading this article at the time of its release. It was about the following: “A strange example was selected here - obviously, with exceptions, the code will be more concise; It looks like an attempt to justify oneself, that one can somehow somehow reduce it . Despite the fact that I have never been a fan of exceptions, the example that is considered in the article directly suggested this comparison. What Pike wanted to say with the phrase “errors this meanings” was not very clear.

At the same time, I understood that I was missing something important, so I gave myself a little time to absorb what I read. And at some point, returning to the article, the understanding came by itself.

Go asks the programmer to treat errors just like any other code. It asks not to consider errors as some special entity for which a special approach / tool / pattern is needed, but to interpret the error handling code as you would the usual logic of your program. Error handling code is not a special construction, it is a complete part of your code, like all the others.
')
Imagine how your thoughts would go if it were a matter of ordinary linguistic construction - variables, conditions, meanings, etc. - and apply them to handling error situations. They are entities of the same level, they are part of logic. You do not ignore the return values ​​of functions without any particular reason, right? You do not ask the language of a special way to work with boolean values, because if is too boring. You do not ask in confusion, “What am I to do if I don’t know what to do with the result of the sqrt function at this nesting level?”. You just write the logic you need.

Once again - errors are normal values, and error handling is the same normal programming.

Let's try to illustrate this with an example similar to the one in the original article. Suppose you have a task - “make several repetitive entries, count the number of bytes written and stop after 1024 bytes”. You will start with a head-on example:
var count, n int
n = write("one")
count += n
if count >= 1024 {
    return
}

n = write("two")
count += n
if count >= 1024 {
    return
}
// etc

play.golang.org/p/8033Wp9xly
, , . , DRY, :
var count int

cntWrite := func(s string) {
  n := write(s)
  count += n
  if count >= 1024 {
    os.Exit(0)
  }
}

cntWrite("one")
cntWrite("two")
cntWrite("three")

play.golang.org/p/Hd12rk6wNk
, , . os.Exit , … ? — , , , , . writer- :
type cntWriter struct {
    count int
    w io.Writer
}

func (cw *cntWriter) write(s string) {
    if cw.count >= 1024 {
        return 
    }
    n := write(s)
    cw.count += n
}

func (cw *cntWriter) written() int { return cw.count }

func main() {
    cw := &cntWriter{}
    cw.write("one")
    cw.write("two")
    cw.write("three")

    fmt.Printf("Written %d bytes\n", cw.count)
}

play.golang.org/p/66Xd1fD8II

— writer , , . , , .

«counter» «error value» -- . , . «» , «» 1024 — .



— — « » « », . , - , . , .

, , , . - , Go , , , . , — .

, . . Go , . , , , , . , , .

« » — .

PS. .

Source: https://habr.com/ru/post/270027/


All Articles