Agreed, Tim.

This discussion helped me to realise that try/catch is pretty good; e.g. we 
never even bothered discussing this topic in our C++ 
code http://mechsys.nongnu.org/ at all...

In the end of the day, we want to treat ALL errors (obviously...).

Go is great that we have two approaches.

Right now I'm changing my code to panic/recover and it's looking good (so 
far): 
https://github.com/cpmech/gosl/commit/16924f154a848e01a070dc7f86d7f4a3962a0af8

Cheers.
Dorival

On Thursday, September 7, 2017 at 6:37:21 PM UTC+10, Tim Uckun wrote:
>
> Totally not a go programmer but here are my worthless two cents.
>
>
>
> I don't see anything wrong with the try catch paradigm, you can choose 
> your granularity. If you want to check every call then you can, if you want 
> to let a few cluster together you can. You guys make is sound like go style 
> error handling is the only way to catch errors at every step. That's not 
> true at all.  
>
> Surely something can be done about the boilerplate if err != nil  maybe 
> shorten that to iferr or something like that. In fact why can't "err" be a 
> language construct where you raise something and it goes into an err[] 
> array. At any time you can check to see what's in there. That would clean 
> up the code so much.
>
> result = doSomething()
> iferr {
>    error = err.pop()
> }
>
> Isn't that so much more readable? 
>
> You could even create checkpoints
>
> raiseErrors()
> // from now on all errors are raised and the program halts
> do()
> some()
> tasks()
> collectErrors()
> // from now on program doesn't halt but err[] array is populated
> do()
> other()
> things()
> dealWithErrArray() // it's global so need to pass it in
> raiseErrors()
> // back to raising them.
>
> As I said none of these are particularly nice.  Elixir gives you both ways 
>
>
> def register({email, password}) do  
>   {:ok, pid} = Membership.connect()
>   sql = "select * from membership.register($1, $2);"
>
>   case Postgrex.Connection.query(pid, sql, [email, password]) do
>     {:ok, res} ->
>       cols = res.columns
>       [first_row | _] = res.rows
>       [new_id, validation_token, auth_token, success, message] = first_row
>       {:ok, %RegistrationResult{
>         success: success,
>         message: message,
>         new_id: new_id,
>         authentication_token: auth_token,
>         validation_token: validation_token
>     }}
>
>     {:error, err} -> {:error, err}
>   end
> end  
>
>
> try do
>   opts
>   |> Keyword.fetch!(:source_file)
>   |> File.read!
> rescue
>   e in KeyError -> IO.puts "missing :source_file option"
>   e in File.Error -> IO.puts "unable to read source file"
> end
>
> As somebody who has just started learning go I can't find any 
> justification for the insane amount of boilerplate go error handling 
> inflicts on the programmer.  Surely there is a a better way.
>
>
>
> On Wednesday, September 6, 2017 at 8:54:38 PM UTC+12, Henry wrote:
>>
>> I use what I would call as *error context*.
>>
>> Here is the simple definition of the *error context*:
>>
>> type ErrorContext interface {
>>     ContainsError() bool
>>     SetError(err error)
>>     Error() error
>> }
>>
>> Here is how you would use it inside the error-prone function:
>>
>> func FragileFunction(ctx ErrorContext) {
>>     if ctx.ContainsError() {
>>         return
>>     }
>>
>>     //some processing ...
>>     //if there is an error
>>     ctx.SetError(errors.New("some error"))  
>>     return
>> }
>>
>>
>> It allows you to do this:
>>
>> ctx := NewErrorContext()
>>
>> fridge := GetFridge(ctx)
>> egg := GetEgg(fridge, ctx) 
>> mixedEgg := MixAndSeason(egg, ctx)
>> friedEgg := Fry(mixedEgg, ctx)
>>
>> if ctx.ContainsError() {
>>     fmt.Printf("failed to fry eggs: %s", ctx.Error().Error())
>> }
>>
>> Or you can even do this:
>>
>> ctxA := NewErrorContext()
>> ctxB := NewErrorContext()
>> ignored := NewErrorContext()
>>
>> a := DoSomethingOne(ctxA)
>> b := DoSomethingTwo(a, ctxA)
>> c,d := DoSomethingThree(b, ctxB) //different context
>> if ctxB.ContainsError() {
>>    c = 1
>>    d = 2
>> }
>> e := DoSomethingFour(c, d, ctxA)
>> if ctxA.ContainsError() {
>>     fmt.Println("Failed To do A")
>> }
>>
>> DoSomething(e, ignored) //error is ignored
>>
>> It is up to you how you would implement the error context.
>>
>>
>> On Tuesday, September 5, 2017 at 1:27:20 AM UTC+7, 
>> marti...@programmfabrik.de wrote:
>>
>>> Hi guys,
>>>
>>> at first I though I really like the idea of how Go deals with error 
>>> management and handling, but the more Go code I look at or try to program, 
>>> the more I get scared about checking errors every second line in every 
>>> given block of code.
>>>
>>> Take a look at this example here from "Build Web Application with 
>>> Golang":
>>>
>>> // insert
>>> stmt, err := db.Prepare("INSERT INTO userinfo(username, departname, 
>>> created) values(?,?,?)")
>>> if err != nil {
>>>   // handle error
>>> }
>>> res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09")
>>> if err != nil {
>>>   // handle error
>>> }
>>> id, err := res.LastInsertId()
>>> if err != nil {
>>>   // handle error
>>> }
>>> fmt.Println(id)
>>> // update
>>> stmt, err = db.Prepare("update userinfo set username=? where uid=?")
>>> if err != nil {
>>>   // handle error
>>> }
>>> res, err = stmt.Exec("astaxieupdate", id)
>>> if err != nil {
>>>   // handle error
>>> }
>>> affect, err := res.RowsAffected()
>>> if err != nil {
>>>   // handle error
>>> }
>>>
>>>
>>> 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.
>>>
>>> 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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to