Hacker News new | past | comments | ask | show | jobs | submit login

> 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.




I 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.


> 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.


I 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.


> 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.


It is unclear because it violates the expectations people have about the result of functions: It's either an error or data for further processing, but never both.

A language that uses sum types (whithout any further guarantees) for error handling cannot formally enforce that invariant.

What I called pragmatic was that we may not want that sort of formal guarantee because we may sometimes want to trade conceptual clarity for efficiency.


> A language that uses sum types (whithout any further guarantees) for error handling cannot formally enforce that invariant.

Huh? The invariant is enforceable:

    type result =
      | Success of result_you_want
      | Error of error_info
You just need to be consistent about what you want. First you ask for returning partial successful results alongside error information, then you ask for the exact opposite. You can make a typeful model of lots of things, but first you need to make up your mind.

> trade conceptual clarity for efficiency.

Could you describe where exactly the efficiency gain comes from? If indirection is the problem, well, if anything, the Go approach requires more indirection.


>The invariant is enforceable

No, what you are showing is how an API designer could enforce a particular API design decision. That's fine, but what I'm talking about is how a language designer could enforce the invariants of a particular error handling concept. I think that sum types alone are not sufficient to do that.

But I have to say I really don't like your tone. I'm not asking for one thing and then the exact opposite. I'm simply discussing pros and cons and I'm thinking about the consequences of different designs.

I'll make my mind up when I feel I know enough the subject to do so. If that offends you, then I suggest you talk to someone else.


> No, what you are showing is how an API designer could enforce a particular API design decision. That's fine, but what I'm talking about is how a language designer could enforce the invariants of a particular error handling concept. I think that sum types alone are not sufficient to do that.

Different APIs have different ways to handle errors. The language designer's job is to allow the programmer to express his intention in the most precise way possible.


> 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.

That's exactly what Go's API does: it returns error information and "data for further processing" from the same function call.


Indeed it does. I find that somewhat questionable, and I wonder how a language would have to be designed to prevent (or discourage) that sort of thing. Or if it is something that should be allowed for pragmatic reasons.




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

Search: