4 ms·
I think the point is that while error handling is part of the program logic it is not necessarily part of every functions logic. Sometimes you just want to pass
by thinkharderdev 5y ago
I think the point is that while error handling is part of the program logic it is not necessarily part of every functions logic. Sometimes you just want to pass an error up the stack to be handled at some other error boundary. This is what Rust (with the ? operator and Result type) and functional effect libraries (Scala ZIO or cats-effect) provide. You can ensure at compile time that errors are handled somewhere but each individual function in the call stack can decide whether it wants to explicitly handle an error or just pass it up the stack. And if you just want to pass it up the stack then there is no syntactic overhead associated with it.
- gwd 5y ago> Sometimes you just want to pass an error up the stack to be handled at some other error boundary. Right, but I think the idea is that the programmer should think and decide every time whether that's what you want to do. I haven't programmed in Rust, but I suspect that people use the ? operator more than is ideal because it's so easy.
- thinkharderdev 5y agoProbably so, but I think as long as you ensure the error gets handled somewhere (rather than crashing the program) it is good tradeoff to make. That was the problem (IMHO) with unchecked exceptions in Java. You make everything an unchecked exception because constantly adding code to handle checked exceptions is annoying and verbose, but then if you don't handle the unchecked exceptions somewhere then they crash the JVM. This is where I think the Scala/Rust approach is best. The compiler can force you to handle the error somewhere but there is very little syntactic overhead if you want to ignore an error in any particular function.
- divan 5y ago> And if you just want to pass it up the stack then there is no syntactic overhead associated with it. "Errors are values" means that this situation is not very different from "I just want to pass the result of my sqrt function up the stack" :) By reading code of function that returns the result of computation the next pair of eyes that gonna read this code will clearly see the intent and idea behind the code. The same should be with "unhappy path" – if intent was just to pass error, without caring of annotating it or doing something with it – it should be as clear and explicit as possible. There is another benefit of "syntactic overhead" – incentive to improve the error handling code. I.e. I may not care at the beginning about annotating error, and just use "return err", but later on I want to make error messages more useful, so the "if err != nil {\n return err }\n" structure makes it easy to annotate it. Instead, if Go code was riddled with "?"s or "!"s or whatever syntactic sugar other use, I would not be so eager to switch from "concise and short single-char" to the "bloated 3 line". Incentives matter in coding psychology. I wish more research was done on that. Bottom line, hiding error handling has more long term drawbacks than benefits. PS. I virtually never use "return err" anymore. Always at least annotate the error – it helps error messages readability immensely without resorting to adding wasteful stacktraces.