Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That's what I though, since in Go you also need to declare your error struct and implement the error interface on it.


Which is not something you generally do a lot of. Most functions either pass an error through or simply return a string error through errors.New(). (That's often not a cheat, either; my modules tend to declare the set of errors as globally-exported variables, allowing you to use == to figure out which error you're getting if you care. If your errors don't take parameters that works fine.) And the error interface only has one method instead of three. Less boilerplate in the worst and the common cases, less compile time guarantees.

It is debatable whether passing errors through is a good idea in theory or in practice at scale (two separate questions there). So far it hasn't bit me at all, though, and I've got a good idea of what I'm looking for for such "bitings".

I find in practice there's two types of errors: Errors I know how to do something about, and errors I don't. In the first case, I can only be dealing with a certain restricted set of errors coming back and I must inevitably write special-purpose code for the given error, and in the second, I don't much care about what it is so I often send it along untouched. I haven't found anything that manages to split the difference yet. Even returning a wrapped error is rare in my application code, though it has its place in library code.

I'm also finding in my real code that the ratio turns out to be closer to 1:2 errors I can do something with/errors I can't, which makes the explicit handling not matter so much. (My gut feeling is that if you find you are always just "return err"ering, and especially if you are doing it without thought, you're writing code that is passing up on some robustness.)


Yeah, I agree about wrapping. I actually usually try to avoid just doing return err, because you're losing some context that this code understands that the below code doesn't.... like if you return a FileNotFound error, the caller might not know why you were looking for that file, so you should wrap it and say fmt.Errorf("couldn't find config file: %s", err), that way if the user sees the error message, he'll see "couldn't find config file: open: file not found: foo.yml" instead of just "open: file not found: foo.yml".


Flatting the error to a string isn't a good idea, unless you're sure you're dumping it straight out to the user (and by that I mean literal human, not merely "caller"). If you're returning it from a function, you need to wrap it, as in the Rust examples, so the caller can extract the original if they want to do something about it.


Well, so there's two theories there... there's the theory you're saying, that the caller might want to know it's a filenotfound, and handle it programmatically... and there's the theory that the fact that you're doing file I/O is an implementation detail that callers shouldn't depend on, because it could change. What side of that argument you fall on depends a lot on the specifics of your code, and how much you want to sanitize your errors (and how likely you think callers will actually be able to do something programmatically about an error).

I agree with both sides, and what I do in any particular situation depends a lot of on the details of what I'm doing.


No, this doesn't fit either case. If you are going to return the error details in a way the human user can read, then you really ought to just return them symbolically, because a programmer will start running regexes over your error codes to figure out what happened. If you're going to not show the underlying error, then either be willing to entirely hide it (sometimes appropriate, probably not for the usual IO case but there are internal errors for which a translation is appropriate) or wrap and pass up, but don't wrap and pass up as a string. That's the worst of all worlds.


I'm pretty much never going to feel bad about breaking someone's code that runs a regex over the error message I return. I can't stop people from writing bad code. Then again, I'm also careful to write my own code such that consumers of it always have a reasonable way to programmatically detect all the errors I know exist, and anything else is just "something really unexpected went wrong, here's a string to log if you want to".

There's always going to be a category of errors that your code just doesn't understand. Giving the caller a string to log with some context is a lot better than returning just a generic error with no context. Returning the specific error is also possible, and sometimes that may be appropriate, but it can cause just as many problems as the other way... but at least the guy writing a regex should know better, and anyone who reads his code is going to notice it and tell him it's very likely to break. However, if someone type-checks the error you're returning, that looks like pretty valid code, so it's less likely to get red-flagged.... until you change your implementation, and that code now breaks.

I really don't think we disagree terribly much on this btw. Like I said, it depends a lot on the situation. Defining policies for errors is hard. There's always tradeoffs, like anything else.


Like localizing it, for instance. Having a message is fine, having weakly-typed errors in production-quality code isn't.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: