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

>There isn't a meaningful difference in cumbersomeness between having two try-catch blocks and two if-err blocks. There is a meaningful difference in cumbersomeness between what Go has today and "try foo(try bar())". Which is why it's so unfortunate that the community killed the try proposal.

    Object thing1;
    try {
        thing1 = doStuff();
    } catch(SameException e) {
        // handle error 1
    }

    try {
        return doOtherStuff(thing1);
    } catch(SameException e) {
        // handle error 2
    }
vs

    thing1, err := doStuff()
    if err != nil {
        // Handle error
    }

    thing2, err := doOtherStuff(thing1)
    if err != nil {
        // Handle error
    }

    return thing2
Happy path is flat. Control flow is obvious and simple. I have not much more to add.

>People say this, but in practice any code search reveals that "if err != nil { return err }" is everywhere. I believe that many Go projects aspire to annotate all errors, but much fewer actually do.

https://github.com/search?l=Go&q=%22errors.Wrap%22&type=Code

>Ironically, the nice thing about exceptions, as well as Rust error chaining crates, is that they do this automatically, so in practice programs written in languages with those features tend to have better error diagnostics than Go programs do.

Rust is a different ball game. Rust does not try to be simple. It comes at its own costs. (I like Rust too.)

>Computers are better at doing things consistently than humans are.

These empty platitudes come up frequently when debating language decisions online. But, it's so meaningless in so many dimensions. I mean, we could also 'use the computer' by adding C macros on top of Go and use them to reduce repetitiveness, but I don't think many people will applaud you for it. Simply applying computer code to solve a problem does not constitute good design.

Go's proof is in the pudding. It's been extremely reliable for me in real world applications.



  doOtherStuff(doStuff())
is the happy path, but it's been hidden among lines of noise that do nothing more than return to the callers who know what to do. Generating this using cpp or m4 would suck, but it's still better than not generating it due to wasted effort (especially re-reading) and mistakes.


How often do you actually need to handle those errors differently? In my experience, it is vastly more likely that a function which can throw errors in Java looks like this:

  Stuff foo() throws SameException {
    return doOtherStuff(doStuff())
  }
Whereas in Go the exact same function must be written like this:

  func foo() (Stuff, SameException) {
    thing1, err := doStuff()
    if err != nil {
        return err
    }

    thing2, err := doOtherStuff(thing1)
    if err != nil {
        return err
    }
  }
Propagating is by far the most common "error handling" and Go constantly makes you break the flow of the code to do it.


FWIW when debugging i prefer the second style if for no other reason than that i can place a breakpoint in doOtherStuff while skipping doStuff. Also reading it, it is more obvious that the code calls both doStuff and doOtherStuff (though with just two calls it isn't a big different, imagine having a 2-3 more calls in there).

(also why debuggers still insist on line-based breakpoints is beyond me, why can't i right click at a call and put breakpoint at the call itself instead of the line where the call lies on?)


You could also write the first function body as

  Stuff thing1 = doStuff()
  return doOtherStuff(thung1)
It's still easier to read without the explicit error handling.


After working with Go for a while I actually find code with error handling easier to read because it is more clear to me what it happening. I look for the error handling as an indicator that the code can actually fail vs. code that cannot fail.

And maybe it's because I've developed a very consistent pattern, and when I find that there are too many errors to handle in a function it helps me realize the function is probably doing too much and needs to be split into multiple functions.

IMO it is all about training your brain and being accepting enough to work in the dialect of the land, as opposed to demanding to speak English when living in France. :-)


The fact that it allows for more nesting on a single line is a bug, not a feature, IMO.




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

Search: