I'm working on a Go project right now and I realised I've written 569 "if err != nil": find . -iname "*.go" -exec grep -inH "if err != nil" {} \; | wc -l 569
On Tuesday, September 5, 2017 at 4:57:45 PM UTC+10, Axel Wagner wrote: > > > > On Tue, Sep 5, 2017 at 8:49 AM, <marti...@programmfabrik.de <javascript:>> > wrote: > >> Axel, >> >> thanks for the reply. >> >> As I already replied to Tomas, I am not looking for improvements in this >> particular case where I need to call an SQL database. >> >> An no, I dont want to wrap all function I use into something which >> collects the errors for me. >> >> Let's say you want to log & panic & exit after any error. >> >> How do you do that, without putting code after each statement or wrapping? >> > > You don't. But it's a bad idea. And "I want to make writing bad code > easier" isn't a very convincing argument for a language-change. > > You can't. And that's why I am proposing to be a little bit open to new >> ideas. >> > > And how open are you to the idea that good error handling isn't about > writing the least amount of code or bubbling up an error in the most > efficient way, but about *handling errors*? Because you haven't really > replied to that part. > > (and FTR, one of the points I was making is, that this isn't a new idea. > It's proposed fairly frequently) > > >> Every modern language I know of has some sort of try...catch construct. >> > > Go is modern and doesn't have it. So this seems cherry-picked. > > >> >> >> Martin >> >> >> >> >> On Monday, September 4, 2017 at 10:57:51 PM UTC+2, Axel Wagner wrote: >>> >>> See, e.g. here >>> <https://groups.google.com/d/topic/golang-nuts/ROr5jveMQvg/discussion> or >>> here >>> <https://groups.google.com/d/topic/golang-nuts/68J-mLCC1JI/discussion> for >>> previous discussions of very similar (even mostly identical) proposals. >>> >>> What I always dislike about these kinds of proposals is, that they are >>> encouraging not handling errors, but instead just passing them up-stack. In >>> general, all of the sites where you are checking for errors will signify >>> different error conditions, that should be communicated differently >>> upstream. For example: >>> >>> db.Prepare("INSERT INTO userinfo(username, departname, created) >>> values(?,?,?)") >>> -> This could fail for basically two reasons: Either communication with >>> your database somehow failed (e.g. a broken network connection), in which >>> case you want to return the equivalent of an HTTP 503 error, or the syntax >>> of your statement is wrong, in which case I'd argue panic'ing would be the >>> correct thing - at the very least, returning the equivalent of a 500. >>> >>> stmt.Exec("astaxie", "研发部门", "2012-12-09") >>> -> Either a 503. Or 400, 403, 409… >>> >>> res.LastInsertId() >>> -> 500 or 501? >>> >>> The issue is, that by simply checking for nil and passing it along, you >>> are *not handling your error*. Different error conditions require different >>> error handling and what the correct error handling is, depends heavily on >>> the application. An ENODIR error in one line of code can signify a totally >>> different error condition than the same error two lines later. So all of >>> these proposals are born out of an exception-style idea of how error >>> handling is supposed to work; deep within the call stack something goes >>> wrong and that something is then just bubbled up to be someone else's >>> problem. Good error handling just can't be well abbreviated in this way - >>> at least not generically. It's too application-specific for that. >>> >>> On Mon, Sep 4, 2017 at 8:27 PM, <marti...@programmfabrik.de> wrote: >>> >>>> Seriously? And yes, I have read >>>> https://blog.golang.org/errors-are-values... >>>> >>>> The best case reduction I found is: >>>> >>>> ... >>>> res, err = stmt.Exec("astaxieupdate", id) >>>> checkError(err) >>>> ... >>>> >>>> Still, I need this after each line of calling a function which may >>>> return an error. >>>> >>> >>> A better take-away from that blog post would have been, to orient >>> yourself around the example of a writer given. You could, for example, >>> provide a one-time abstraction that wraps *sql.DB and collects the error. >>> I'd agree that the sql package tends to not be amazing for that, because of >>> its set of interdependent types, it is still possible. For example, with >>> this <https://play.golang.org/p/kdgBUqWeR->, you could write >>> >>> d := &errDB{db: d} >>> stmt := d.Prepare("INSERT INTO…") >>> res := stmt.Exec(…) >>> id := res.LastInsertId() >>> stmt := d.Prepare("UPDATE…") >>> res := stmt.Exec(…, id) >>> affect := res.RowsAffected() >>> return d.err >>> >>> Now… this isn't really nice either (see above. sql isn't really >>> well-designed for this. You'd probably try and implement a driver for this, >>> but sql doesn't make that easy either). And it's a bad idea for all the >>> same reasons the watch-proposal isn't a great idea here. But it illustrates >>> a far more effective take-away from that blog post. >>> >>> >>>> >>>> I bet this is not pleasant to do in larger code bases and it also takes >>>> away focus from what is actually happening. >>>> >>>> 50-80% of all lines of code in my example deal with error handling? >>>> >>>> This is not good. Seriously. >>>> >>>> And don't get me wrong, there is a lot of things I really like, love >>>> and adore about Go, but catching errors needs an improved syntax! >>>> >>>> And I am not proposing try...catch here. >>>> >>>> How about introducing a new piece of syntax >>>> >>>> "watch if .... " >>>> >>>> which tells the compiler to watch out for changes in a given SimpleStmt >>>> >>>> The same code as above would look like this: >>>> >>>> var err Error >>>> >>>> watch if err != nil { >>>> // handle error(s) >>>> } >>>> >>>> // insert >>>> stmt, err := db.Prepare("INSERT INTO userinfo(username, departname, >>>> created) values(?,?,?)") >>>> res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09") >>>> id, err := res.LastInsertId() >>>> fmt.Println(id) >>>> >>>> // update >>>> stmt, err = db.Prepare("update userinfo set username=? where uid=?") >>>> res, err = stmt.Exec("astaxieupdate", id) >>>> affect, err := res.RowsAffected() >>>> >>>> >>>> - The "watch if" would be executed after each assignment of any of >>>> the variables used in SimpleStmt of the statement. >>>> - Multiple "watch if" would be executed in order or appearance >>>> - The "watch if" could be used like "defer..." inside functions >>>> - The "watch if" would work in its full scope of the watched >>>> variables >>>> >>>> I am not a language expert, so may be there is a saner way of >>>> expression what I want to achieve. >>>> >>>> But bottom line is, there should by an easier to read and write way to >>>> deal with errors in Go. >>>> >>>> >>>> Martin >>>> >>>> >>>> >>>> >>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "golang-nuts" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to golang-nuts...@googlegroups.com. >>>> For more options, visit https://groups.google.com/d/optout. >>>> >>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.