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.