logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git

Why-Go-error-handling-doesnt-sit-right-with-me.md (3806B)


  1. ---
  2. date: 2014-06-07
  3. #vim: tw=82
  4. layout: post
  5. title: Go's error handling doesn't sit right with me
  6. tags: [go]
  7. ---
  8. I'll open up by saying that I am not a language designer, and I do like a lot of
  9. things about Go. I just recently figured out how to describe why Go's error
  10. handling mechanics don't sit right with me.
  11. If you aren't familiar with Go, here's an example of how Go programmers might do
  12. error handling:
  13. ```go
  14. result, err := SomethingThatMightGoWrong()
  15. if err != nil {
  16. // Handle error
  17. }
  18. // Proceed
  19. ```
  20. Let's extrapolate this:
  21. ```go
  22. func MightFail() {
  23. result, err := doStuffA()
  24. if err != nil {
  25. // Error handling omitted
  26. }
  27. result, err = doStuffB()
  28. if err != nil {
  29. // Error handling omitted
  30. }
  31. result, err = doStuffC()
  32. if err != nil {
  33. // Error handling omitted
  34. }
  35. result, err = doStuffD()
  36. if err != nil {
  37. // Error handling omitted
  38. }
  39. }
  40. ```
  41. Go has good intentions by removing exceptions. They add a lot of overhead and
  42. returning errors isn't a bad thing in general. However, I spend a lot of my time
  43. writing assembly. Assembly can use similar mechanics, but I'm spoiled by it (I
  44. know, spoiled by assembly?) and I can see how Go could have done better. In
  45. assembly, `goto` (or instructions like it) are the only means you have of
  46. branching. It's not like other languages where it's taboo - you pretty much *have*
  47. to use it. Most assembly also makes it fancy and conditional. For example:
  48. goto condition, label
  49. This would jump to `label` given that `condition` is met. Like Go, assembly
  50. generally doesn't have exceptions or anything similar. In my own personal flavor
  51. of assembly, I have my functions return error codes as well. Here's how it's
  52. different, though. Let's look at some code:
  53. ```
  54. call somethingThatMightFail
  55. jp nz, errorHandler
  56. call somethingThatMightFailB
  57. jp nz, errorHandler
  58. call somethingThatMightFailC
  59. jp nz, errorHandler
  60. call somethingThatMightFailD
  61. jp nz, errorHandler
  62. ```
  63. The difference here is that all functions return errors in the same way - by
  64. resetting the Z flag. If that flag is set, we do a quick branch (the `jp`
  65. instruction is short for `jump`) to the error handler. It's not clear from looking
  66. at this snippet, but the error code is stored in the A register, which the
  67. `errorHandler` recognizes as an error code and shows an appropriate message for.
  68. We can have one error handler for an entire procedure, and it feels natural.
  69. In Go, you have to put an if statement here. Each error caught costs you three
  70. lines of code in the middle of your important logic flow. With languages that
  71. throw exceptions, you have all the logic in a readable procedure, and some error
  72. handling at the end of it all. With Go, you have to throw a bunch of
  73. 3-line-minimum error handlers all over the middle of your procedure.
  74. In my examples, you can still return errors like this, but you can do so with a
  75. lot less visual clutter. One line of error handling is better than 3 lines, if you
  76. ask me. Also, no one gives a damn how you format assembly code, so if you wanted
  77. to do something like this you'd be fine:
  78. ```
  79. call somethingThatMightFail
  80. jp nz, errorHandler
  81. call somethingThatMightFailB
  82. jp nz, errorHandler
  83. call somethingThatMightFailC
  84. jp nz, errorHandler
  85. call somethingThatMightFailD
  86. jp nz, errorHandler
  87. ```
  88. Or something like this:
  89. ```
  90. call somethingThatMightFail \ jp nz, errorHandler
  91. call somethingThatMightFailB \ jp nz, errorHandler
  92. call somethingThatMightFailC \ jp nz, errorHandler
  93. call somethingThatMightFailD \ jp nz, errorHandler
  94. ```
  95. The point is, I think Go's error handling stuff make your code harder to read and
  96. more tedious to write. The basic idea - return errors instead of throwing them -
  97. has good intentions. It's just that how they've done it isn't so great.