Skip to content

Instantly share code, notes, and snippets.

@mattdee123
Last active February 20, 2019 03:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattdee123/a04f95ef5639489668cafd9c3b675a8c to your computer and use it in GitHub Desktop.
Save mattdee123/a04f95ef5639489668cafd9c3b675a8c to your computer and use it in GitHub Desktop.
Error Handling Should Support Custom Error Types

Overall, the proposal seems great. However, one of the things I love about go is that the error type is not special (other than the fact that it doesn't require importing). This proposal seems to special-case the error type, adding extra barriers to defining ones own error types.

As an example, I was building an interpreter, and I wanted all of my parser's error messages to have a file position (line/column number) on them. By defining a new type,

type PosError interface{
  error
  Pos() FilePos
}

and making all of my functions return it, the compiler is able to remind me where I need to add a file position, since if I don't, typechecking will fail.

In this way, it is possible to guarantee that an error value will have extra information, without needing type assertions at all.

However, this new proposal appears to only work on functions whose last return value is of type error. As far as I can tell, if the handle statement took in a variable name and a variable type, it would be possible to have handle functions for arbitrary types.

func foo() MyErrorType {
  handle err MyErrorType {
    return err.Wrap("some context") // or you could just use the default handler
  }
  // now, I can check any function whos last return value is a MyErrorType.
}

In my mind, this also helps greatly for the error values issue, since it supports using custom error values where needed.

Please feel free to comment if there's something I have missed, but this seems to me like a pretty natural extension of the idea that errors are just like any other values.

@songtianyi
Copy link

agree!

@sauerbraten
Copy link

Under https://github.com/golang/proposal/blob/master/design/go2draft-error-handling.md#keyword-try-versus-check, the draft says

check allows checking of any expression that is assignable to error

so your custom error type would be handled as well. It's true of course that this requires something like posErr := err.(PosError) in your handle block to get your more useful, custom type, and also because your function would not have a default handler and using check inside the function means you have to provide one that returns PosError (assuming your function returns that). So this should work:

func foo() PosError {
  handle err {
    posErr := err.(PosError)
    return posErr
  }

  check functionReturningPosError()
}

Then, as long as you make sure your functions return PosError, the compiler will still remind you when you try to return the wrong type anywhere outside the handle block.

I'm not sure if an unchecked type assertion is something that should be done in a handle block though. Maybe it's more desirable to refactor your custom error to use the proposed new error values and wrap the err variable of type error which you get in the handle block before passing it down as a "normal" error. The code calling foo could then inspect the error and check for PosError. You would lose the compile-time check for PosError, though.

@networkimprov
Copy link

@mattdee123 I added your custom-types concept to my feedback gist, thank you.

@tgoikawa
Copy link

agree!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment