Although I’m not a go developer I love to check out new languages and concepts they bring. I never really liked the cluttering aspect of error handling in go but this check handle pattern is really confusing.
In the examples from another comment, there were multiple handle blocks. Which one is going to be used? How can I handle two different errors in the same scope differently. Why is the handle block before the check block?
The handle blocks chain. Once an handle block is reached, it becomes part of the chain. If an error occurs, the blocks execute from the bottommost block to the topmost. (It is proposed to remove the chaining functionality, though)
If you simply want to add functionality, just add another handle block when you want that functionality to start being used. (Like the file-copy example I have in the post). Otherwise you'll have to do the standard if err != nil
There's a few reasons behind this:
a. It's easier to think about needing to "declare" your handle blocks. You can't use a handle block if it hasn't been declared yet!
b. It makes for much faster compile times to require handle blocks.
c. It makes it more similar to how defer works (if you don't know Go this doesn't mean much)
d. Enabling a handle block to be after a check block means that the handle block may have more variables in it's scope than what was at the check block...
// Demonstrates why `handle` must be above `check`funcErrorTesting(){checkerrors.New("some kind of error")// will go to handle blocki:=5handleerr{log.Fatalf("i=%d, err=%v",i,err)// Since we got here from the top line, i has not been declared!}}
Maybe I shouldn’t do this, but in my head I compare this to the try/catch/finally concept. Catch comes after try but cannot use any variables that have not been declared before try. But it makes the flow much clearer since you usually read code from top to bottom.
And one of my questions was how to implement multiple catch blocks. With try/catch i can have muktiple of those constructs or even multiple catch blocks. Let’s say I have file operation and a parsing operation and I want to handle them differently, I could declare two different catch blocks. How would I do this with check/handle?
In current Go with the handle construct would look something like this:
handleerr{ifnotExist,ok:=err.(*os.ErrNotExist);ok{// Do stuff with notExist}elseifotherErr,ok:=err.(*pack.OtherErr);ok{// Do stuff with otherErr}}// Or if your list is very longhandleerr{switcherr.(type){case*os.ErrNotExist:// Code...case...:// ...default:// ...}}
Note that the notExist, ok := err.(*os.ErrNotExist) is how you typecast in Go. Also, a semicolon in an if statement means "just execute the left side normally and evaluate the right side as the condition", although any variables declared on the left side have block scope within the if statement.
Errors in Go are just an interface, so you just cast them to the error that you want to check.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Although I’m not a go developer I love to check out new languages and concepts they bring. I never really liked the cluttering aspect of error handling in go but this check handle pattern is really confusing.
In the examples from another comment, there were multiple handle blocks. Which one is going to be used? How can I handle two different errors in the same scope differently. Why is the handle block before the check block?
To answer your questions -
The
handle
blocks chain. Once anhandle
block is reached, it becomes part of the chain. If an error occurs, the blocks execute from the bottommost block to the topmost. (It is proposed to remove the chaining functionality, though)If you simply want to add functionality, just add another handle block when you want that functionality to start being used. (Like the file-copy example I have in the post). Otherwise you'll have to do the standard
if err != nil
There's a few reasons behind this:
a. It's easier to think about needing to "declare" your handle blocks. You can't use a handle block if it hasn't been declared yet!
b. It makes for much faster compile times to require handle blocks.
c. It makes it more similar to how
defer
works (if you don't know Go this doesn't mean much)d. Enabling a handle block to be after a check block means that the handle block may have more variables in it's scope than what was at the check block...
Thanks for your elaborate reply.
Maybe I shouldn’t do this, but in my head I compare this to the try/catch/finally concept. Catch comes after try but cannot use any variables that have not been declared before try. But it makes the flow much clearer since you usually read code from top to bottom.
And one of my questions was how to implement multiple catch blocks. With try/catch i can have muktiple of those constructs or even multiple catch blocks. Let’s say I have file operation and a parsing operation and I want to handle them differently, I could declare two different catch blocks. How would I do this with check/handle?
It would look something like this:
In current Go with the handle construct would look something like this:
Note that the
notExist, ok := err.(*os.ErrNotExist)
is how you typecast in Go. Also, a semicolon in an if statement means "just execute the left side normally and evaluate the right side as the condition", although any variables declared on the left side have block scope within the if statement.Errors in Go are just an interface, so you just cast them to the error that you want to check.