4 ms·
FWIW, I don't have anything against checking errors - I agree that it's preferable to exceptions, but the way it happens to be done in Go is rather distasteful.
by catnaroek 10y ago
FWIW, I don't have anything against checking errors - I agree that it's preferable to exceptions, but the way it happens to be done in Go is rather distasteful. A sum type, as suggested by TheDong, would make things clearer, by statically forcing the alternatives to be:
(0) A correct result (and no error object)
(1) An error object (and no correct result)
Ruling out:
(0) Both a correct result and an error object
(1) Neither a correct result nor an error object
By “ruling out”, I mean “it's a compile error”, rather than “it's a pattern, and the community won't appreciate it if you deviate from it”.
Panics as normal control flow are just as unidiomatic in Rust as they are in Go, but at least:
(0) There's a decent (in fact, superior) alternative for error handling.
(1) You don't risk leaking resources. RAII has that covered.
- fauigerzigerk 10y agoI like the conceptual clarity of sum types, but in some cases they may not be flexible enough (same as exceptions). Consider the case of io.Reader: https://golang.org/pkg/io/#Reader https://golang.org/pkg/io/#Reader Read always returns the number of bytes read, and if an error occurs after some bytes have been read (or at EOF) it returns that error as well. It does feel a little dirty, but it's also efficient and pragmatic.
- catnaroek 10y ago> Read always returns the number of bytes read, and if an error occurs after some bytes have been read (or at EOF) it returns that error as well. Sum types can do this as well. In OCaml syntax: type result = | Success of int (* bytes read = buffer length *) | Error of int * err_info (* bytes read, error info *) class type reader = object (* attempt to fill the buffer *) method read : buffer -> result end > It does feel a little dirty, but it's also efficient and pragmatic. The pragmatic thing to do is to make illegal states irrepresentable, so that the programmer doesn't have to worry about them. There's literally no benefit to losing conceptual clarity.
- fauigerzigerk 10y agoI understand why this may be formally preferrable, but it still suffers from the same conceptual clarity issues. What I mean by conceptual clarity is knowing for sure, without looking at the documentation of each function, that it returns either an error or data for further processing, but never both. That's not the case with your solution either. You're just packaging the same conceptual ambiguity in a slightly different way.
- catnaroek 10y ago> That's not the case with your solution either. It is. A single call to the `read` method of a `reader` object returns either `Success` or `Error`, but never both. It's handled like this: match my_reader#read my_buffer with | Success(len) -> (* success logic *) | Error(len,info) -> (* error-handling logic *) > You're just packaging the same conceptual ambiguity in a slightly different way. There's no ambiguity whatsoever. The cases are separate, and you can't use the variables of one case when handling the other. There's still literally no reason to sacrifice conceptual clarity.
- fauigerzigerk 10y agoI don't dispute the formal correctness of your solution or its theoretical desirability. But your solution cannot fix the conceptual lack of clarity that follows from the decision of the API designer to return both error information and data for further processing from the same function call. It's not a formal problem.
- catnaroek 10y ago> But your solution cannot fix the conceptual lack of clarity that follows from the decision of the API designer to return both error information and data for further processing from the same function call. Why is it unclear? If the API supports using a reader after an error happens, the types have to reflect just that. It's not the kind of API I would design, but it's what you asked for. > It's not a formal problem. The inability to express your intention in a mechanically enforceable way is very much a formal problem.