← Back to context

Comment by gary_0

5 years ago

The problem of error handling arises due to type systems and function call semantics.

  data = open("/var/foo")

Most programmers are going to expect 'data', the result returned by 'open', to be a type that allows reading/writing the file. The programmer expects /var/foo to exist, or they might have checked before calling 'open', but even that's not foolproof.

Historically, a failure might just set 'data' to an invalid value (like 0 or null) but that ended up being a bad idea. And we needed some way to return more information about the error. So we started doing this:

  error = open(data, "/var/foo")

But this mainly just complicated things. Is 'data' input or output? The function doesn't return its actual output. And it's still possible to ignore 'error', so 'data' is still potentially undefined.

Then exceptions were invented so we could use proper function call styles again, and the program wouldn't go into an undefined state. Instead, the error could be handled with separate logic, or the program would halt if it was ignored. This was far from a perfect solution, though.

Then sum types entered the mainstream, so 'data' had well-defined ways of returning something other than the expected result. But that resulted in a lot of competing conventions and stylistic decisions for what to do when 'data' is an error type, that haven't quite been settled yet.

Again referring to Go's imperfect but interesting handling of this problem, the style in Go would be:

  data, err := open("/var/foo")
  if err != nil....

In fact, the compiler will make you deal with both values after assignment unless you explicitly ignore one of the return values.