Live data from Hacker News

Eris – A better way to handle, trace, and log errors in Go

github.com

11–20 of 61 posts

Re: Eris – A better way to handle, trace, and log errors in Go

#11

Have spent a while in the py/js world but have switched to rust/go for part of this year -- biggest change is boilerplate relating to error handling. Automatic stack capture for exceptions is something my language could conceivably do on my behalf. Writing even 3 lines of code per function to propogate up the error is a huge pain, especially because it pollutes the return type -- MustWhatever() in go is much easier t…

You're fighting the language. Unless you're writing prototypes where crashing doesn't matter, you should be writing error handling code first, and your business logic second -- so-called "sad path first" programming, c.f. "happy-path first" programming that you usually do in languages with exceptions like Python.

I'm super into the error handling philosophies of Go and Rust, but I don't think either of them is "sad path first". That implies that you can think about your error cases in a meaningful way before you have concrete business logic, which seems unlikely.

Re: Eris – A better way to handle, trace, and log errors in Go

#12

Have spent a while in the py/js world but have switched to rust/go for part of this year -- biggest change is boilerplate relating to error handling. Automatic stack capture for exceptions is something my language could conceivably do on my behalf. Writing even 3 lines of code per function to propogate up the error is a huge pain, especially because it pollutes the return type -- MustWhatever() in go is much easier t…

Rust has a postfix `?` operator to propagate errors up the call stack.

Re: Eris – A better way to handle, trace, and log errors in Go

#13
post #12

Have spent a while in the py/js world but have switched to rust/go for part of this year -- biggest change is boilerplate relating to error handling. Automatic stack capture for exceptions is something my language could conceivably do on my behalf. Writing even 3 lines of code per function to propogate up the error is a huge pain, especially because it pollutes the return type -- MustWhatever() in go is much easier t…

Rust has a postfix `?` operator to propagate errors up the call stack.

as I understand it, this requires an Option or Result return type that matches the type of the statement

The ? operator is better than nothing, but I still need my error types to match all the way up the stack

Re: Eris – A better way to handle, trace, and log errors in Go

#14

Have spent a while in the py/js world but have switched to rust/go for part of this year -- biggest change is boilerplate relating to error handling. Automatic stack capture for exceptions is something my language could conceivably do on my behalf. Writing even 3 lines of code per function to propogate up the error is a huge pain, especially because it pollutes the return type -- MustWhatever() in go is much easier t…

I don’t buy the “huge pain” argument. I write lots of Python and Go, and the error boilerplate is a non-issue. I also appreciate that it’s explicit instead of implicit.

Re: Eris – A better way to handle, trace, and log errors in Go

#15
post #12

Earlier quoted context omitted.

Rust has a postfix `?` operator to propagate errors up the call stack.

as I understand it, this requires an Option or Result return type that matches the type of the statement The ? operator is better than nothing, but I still need my error types to match all the way up the stack

It doesn’t require it. Instead it could just generate the same error handling boilerplate. But I think it would be a mistake versus general purpose (generic) sum types a la Rust.

Re: Eris – A better way to handle, trace, and log errors in Go

#16

Earlier quoted context omitted.

You're fighting the language. Unless you're writing prototypes where crashing doesn't matter, you should be writing error handling code first, and your business logic second -- so-called "sad path first" programming, c.f. "happy-path first" programming that you usually do in languages with exceptions like Python.

I'm super into the error handling philosophies of Go and Rust, but I don't think either of them is "sad path first". That implies that you can think about your error cases in a meaningful way before you have concrete business logic, which seems unlikely.

Of course you can. Sad path first means, after you write your data types and interface signatures, writing the first stub implementations as

    func (t *Thing) Process(id int) (string, error) {
        return "", fmt.Errorf("not implemented")
    }
and then filling them in gradually like

    func (t *Thing) Process(id int) (string, error) {
        dat, err := t.store.Read(id)
        if err != nil {
            return "", fmt.Errorf("error reading ID: %w", err)
        }
        
        cert, err := dat.ExtractCertificate()
        if err != nil {
            return "", fmt.Errorf("error extracting certificate: %w", err)
        }
        
        return cert.Name(), nil
    }
and explicitly not

    func (t *Thing) Process(id int) (string, error) {
        dat, _ := t.store.Read(id)          // TODO: error handling
        cert, _ := dat.ExtractCertificate() // TODO: error handling
        return cert.Name(), nil
    }
Writing code this way, explicit error handling upfront, is fundamental to reliability (for a large class of applications).

Re: Eris – A better way to handle, trace, and log errors in Go

#18
post #12

Earlier quoted context omitted.

Rust has a postfix `?` operator to propagate errors up the call stack.

as I understand it, this requires an Option or Result return type that matches the type of the statement The ? operator is better than nothing, but I still need my error types to match all the way up the stack

AFAIK if you properly define the From/To operator, rust generates it for you.

And if you think about it, defining those operator is a good practice as it tells your program how to handle errors.

Re: Eris – A better way to handle, trace, and log errors in Go

#19
post #14

Have spent a while in the py/js world but have switched to rust/go for part of this year -- biggest change is boilerplate relating to error handling. Automatic stack capture for exceptions is something my language could conceivably do on my behalf. Writing even 3 lines of code per function to propogate up the error is a huge pain, especially because it pollutes the return type -- MustWhatever() in go is much easier t…

I don’t buy the “huge pain” argument. I write lots of Python and Go, and the error boilerplate is a non-issue. I also appreciate that it’s explicit instead of implicit.

It's not just a pain to write. I've accidentally introduced way more bugs through Go style error handling than through Python style error handling. Some examples:

Forgetting that a function returns an error:

  ...
  foo() // foo returns an error that isn't being handled.
  ...
Forgetting to check the error returned by a function. Note a linter won't pick this up since the err variable is used later.

  ...
  err := foo()
  err = bar() // The previous error will go unhandled.
  ...
Accidentally typing return nil instead of return err:

   ...
   if err != nil {
       return nil
   }
   ...
And in the case of the errors library, there's times where I will call a builtin function that returns an error and forget to call errors.WithStack. Every once in a while I'll come across an error without a stack trace and I'll have to hunt down where it came from:

  ...
  err := json.Unmarshal(bytes, &obj)
  if err != nil {
      return err // should be errors.WithStack(err)
  }
  ...
All of these issues look just like normal bug free Go code. On the basis that I've introduced more bugs this way, I prefer Python style error handling by far.

Re: Eris – A better way to handle, trace, and log errors in Go

#20
post #14

Earlier quoted context omitted.

I don’t buy the “huge pain” argument. I write lots of Python and Go, and the error boilerplate is a non-issue. I also appreciate that it’s explicit instead of implicit.

It's not just a pain to write. I've accidentally introduced way more bugs through Go style error handling than through Python style error handling. Some examples: Forgetting that a function returns an error: ... foo() // foo returns an error that isn't being handled. ... Forgetting to check the error returned by a function. Note a linter won't pick this up since the err variable is used later. ... err := foo() err =…

> All of these issues look just like normal bug free Go code.

Not to me.

Post reply on HN