5 ms·
> Errors quickly lose their usefulness if you simply pass them up the stack. Nope, not in languages where you have a stacktrace attached. > Errors simply pass
by valenterry 2y ago
> Errors quickly lose their usefulness if you simply pass them up the stack.
Nope, not in languages where you have a stacktrace attached.
> Errors simply passed up the stack are, more often than not, going to leak implementation details.
That's why in a good language you can just wrap them at the right level of abstraction.
- deleted 2y ago[deleted]
- 9rx 2y ago> Nope, not in languages where you have a stacktrace attached. Like you say, the stack trace needs to be attached. For that you, at very least, need a "sidecar" handler if not done so in the same execution path, as we discussed earlier. Did you, uh, forget to read the thread? > That's why in a good language you can just wrap them at the right level of abstraction. You can move the logic around, but you can't avoid it, as we discussed earlier. Did you, uh, forget to read the thread?
- valenterry 2y ago> Like you say, the stack trace needs to be attached. For that you, at very least, need a "sidecar" handler if not done so in the same execution path, as we discussed earlier. Did you, uh, forget to read the thread? I just read it again, but I'm not sure what you mean. And sorry, I'm not familiar with that terminology (sidecar) but from the perspective of the user/developer, does it matter? As system or library developer, I don't need to do anything - I'll have the stacktrace available when I need it. There is extra code necessary. (one has to be mindful of the performance, but that's it) > You can move the logic around, but you can't avoid it, as we discussed earlier. Did you, uh, forget to read the thread? Doesn't have to do anything with moving logic around. Let's say you are function foo and you call other functions and one of them is bar and it will fail with barError. Then, to avoid breaking your (= foo's) consumers if bar changes its internals, you simple wrap bar's error with your own. That can be as simple as doing `bar.mapError(barError -> fooError(cause = barError))` and that's it. That is all I wanted to say. Then, depending on the language, you stil don't have to repeatedly do "`if err != nil {}`" or so. There are enough alternatives, e.g. monadic error handling like in Haskell or macros like in Rust.
- 9rx 2y ago> And sorry, I'm not familiar with that terminology (sidecar) You were familiar with it earlier – you couldn't have sensibly replied otherwise. How did you manage to lose it in the meantime? > That can be as simple as doing `bar.mapError(barError -> fooError(cause = barError))` and that's it. At the end of the day is that really any different than: `err = errors.Join(MyError{}, err)`? But you've still just moved logic around (e.g. into mapError/Join). You've not changed what needs to be done.
- valenterry 2y ago> At the end of the day is that really any different than: `err = errors.Join(MyError{}, err)`? In the end, everything is machine code. You tell me if that is any different or not. > But you've still just moved logic around (e.g. into mapError/Join) To improve backwards compatibility, yeah. Somehow the error needs to be changed. But: with a stacktrace and a good language, this is a single line of code. No if/else etc. needed, even in the case of multiple different errors in different places in foo. And my impression was that this is what we were discussing here - ergonomics of error handling.
- 9rx 2y ago> In the end, everything is machine code. Code is ultimately written for humans, not machines. If we only cared about the machine you could flip toggle switches and not worry about all these pesky human problems found in understanding code. > You tell me if that is any different or not. I don't think there is. But I may have missed your intent. The question was posed to ensure that we are on the same page. If you leave it up to me, we are on the same page, which means your earlier comment really doesn't work. There is no `if err != nil` to be found. > But: with a stacktrace and a good language, this is a single line of code. Why can't it be a single line of code in Go? In fact, at one point Go even did include the stack trace in that single line of code in some pre-release work, but real-world usage determined that nobody ever used it (all the information you need is already there without a stack trace!), so it was stricken before final delivery. You can still do it yourself if you want, though. Errors are not magic.