3 ms·
> I'm not sure why it gets brought up other than language level FOMO. I think it gets brought up because people see places it would be helpful quite often. A
by TheDong 2y ago
> I'm not sure why it gets brought up other than language level FOMO.
I think it gets brought up because people see places it would be helpful quite often.
A lot of the Go code I've written has:
switch x {
case ....:
case ....:
default:
panic(fmt.Sprintf("inexhaustive match, please update this switch statement for %v", x))
}
Similarly, go supposedly has good error handling, but I constantly find myself writing:
switch {
case err == nil:
case errors.Is(err, SomeErr):
// handle SomeErr
case errors.Is(err, OtherErr):
// handle OtherErr
case strings.Contains(err.Error(), "tls: unknown certificate authority")):
// handle unexported go stdlib error, XXX fix after https://github.com/golang/go/issues/35234
default:
panic(fmt.Sprintf("unhandled error type: %v: %T", err, err))
}
Like, for being a statically typed language, Go's error handling is really bad, and sum types is the thing that would let me internally at least make error handling feel good.
I could have my own functions return up a non `error`-interface type, not implement the `error` interface intentionally to avoid the nil-typed-interface problem 'err' is otherwise prone to, and then I could actually know when I compiled my codebase that my error handling is good, and know what needs to be updated after adding new error paths.
- XorNot 2y agoI mean...I'll say this, for all the great things spoken about it I also found myself wildly disappointed with Rust's error handling when I tried to use it (and then a pile of blog posts going "oh yeah, it does kind of suck..."). What I am yet to find in any programming language is a reliable way to put my cursor somewhere in the code base, and know exactly all the possible errors which can happen, where they could come from, and whether I've handled them (or might be interested in handling them). Fault-injection is also consistently a sore point - i.e. in Go if you're doing an os.Open(somefile) call - it'd be really nice if writing code which tests the failure path was just easier - i.e. most of the time I'm saying "this Open on this line, just return an error for this test case so I can make sure it does what I want" - without bogging myself down in dependency injection or call monitoring (i.e. realistically I just want to say "os.Open in file somefile.go, line 143 - for this test please just return err"). Yes something like this can be done, but can we really not make this easier? Write tools which make this easier?
- rto_victim 2y agoAgreed. Sum types require too much boilerplate for error handling as they require wrapping and unwrapping which leads to people creating crate-level error enums that have every possible injection. Ideally we'd have unions which gets rid of the bike shedding that comes with sums [1]. [1]: https://gvolpe.com/blog/error-handling-scala3/ https://gvolpe.com/blog/error-handling-scala3/
- andyferris 2y agoRoc's polymorphic tagged unions seem to be the sweet spot of not requiring specially-crafted enums or multiple levels of unwrapping, yet having lots of statically-checked guarantees. (Zig is similar but doesn't support different types of payloads on the different error values).
- tubthumper8 2y agoUntagged unions lack the ability to model "the success value is a string and the error is a string", right?
- rto_victim 2y agoThat's correct. In your case you can either model it with a sum type or wrap each variant in its own type and take the union of them. Example: enum Result { Success(String), Error(String), } struct Success(String); struct Error(String); type Result = Success | Error;
- fao_ 2y ago> What I am yet to find in any programming language is a reliable way to put my cursor somewhere in the code base, and know exactly all the possible errors which can happen, where they could come from, and whether I've handled them (or might be interested in handling them). Zig's error types and error unions seem like a decent approach to achieve this.
- metaltyphoon 2y ago
- tucnak 2y agoI'm not bothered to `switch` errors, however I really wish I could also match against both static errors (ErrSomethings) and error _types_ in a single `switch`, because now whenever I want to properly handle most errors, I need at least two `switch` statements. There's also the issue of type-matching deeply-wrapped types which is non-trivial (requiring a for loop.) If only they could solve this syntactically...