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.

Reply via email to