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, <[email protected] <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, <[email protected]> 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 [email protected].
>>>> 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 [email protected] <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 [email protected].
For more options, visit https://groups.google.com/d/optout.