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

You're right, but I still think they have a point. What I miss from `error.Is/As` is exhaustive matching. I'd love a way to statically guarantee I haven't missed an important error type. It really comes back to the absence of sum types.




Yeah, the lack of sum types of any kind in Go is the only thing that I really miss when coming back from Rust. It's, I think, a big part of the reason that Gleam has seen a lot of growth. It has many of the syntactic benefits of Go with the compiler guarantees of Rust (though it's weird in some other ways, like dramatically favoring continuation-passing-style in programmer facing syntax).

> I'd love a way to statically guarantee I haven't missed an important error type.

It wouldn't be hard — rather easy, even — to write a static analyzer for that if you constrained your expectations to cases where sum types could practically be used. No reason to not do it right now!

But sum types don't really solve for a lot of cases. Even in Go you can add additional constraints to errors to get something approaching sum types. You don't have to use a naked `error`. But you are bound to start feeling pain down the road if you try. There is good reason why even the languages that support defined error sets have trended back to using open-ended constructs.

It does sound great in theory, no doubt, but reality is not so kind.


> There is good reason why even the languages that support defined error sets have trended back to using open-ended constructs.

Rust does it that way & has never trended in any other direction. The generally-accepted wisdom is "thiserror¹ for libraries, anyhow² for applications"—i.e., any error that's liable to be handled by a machine should be an enum of exhaustively-matchable error kinds, whereas anything that's just being propagated to the user should be stringified & decorated with context as it bubbles up.

Certainly, unified error types which wrap and erase more specific errors are sometimes desirable, but equally they often are not. Languages which support exhaustive matching support both, permitting us to choose based on context.

[1]: https://docs.rs/thiserror/latest/thiserror/

[2]: https://docs.rs/anyhow/latest/anyhow/


Exhaustive matching is terrible for backward/forward compatibility.

Yeah, your error handling should not always be backwards/forwards compatible. If the new version of a library is throwing a new kind of error, that library's clients need to be updated. Being able to break your clients when necessary is a feature & not a bug. Of course, if you don't need to break your clients, simply don't change your ErrorKind enum.

Backwards/forwards compatibility matters a lot across service boundaries. I'm not saying Protobuf needs to be exhaustively matchable. But native types from a static library? You want to be able to match those exhaustively.




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

Search: