Re: [go-nuts] More palatable exception handling

147 views
Skip to first unread message

Patrick Mylund Nielsen

unread,
Jun 28, 2012, 8:39:01 PM6/28/12
to karl.p...@gmail.com, golan...@googlegroups.com
I think you'll come to like this quite quickly if you write a few applications in Go. If err != nil {...} can get a little verbose, but I find it results in more robust applications. When functions let errors "bubble up", they do so explicitly. I initially had the same impression as you, but have come to love it.

Here's a pretty good argument for Go's approach: http://dave.cheney.net/why-go-gets-exceptions-right

Go already has "exceptions", panic() and recover(), but they shouldn't be used as such. You panic when you simply can't do something (usually in functions where you wouldn't usually need, or where it is impractical, to return an error), and recover only if your application has some way around that, e.g. to continue running even if you e.g. tried to get or set an invalid value using reflection, or there was a panic while handling an HTTP request.

On Fri, Jun 29, 2012 at 1:33 AM, <karl.p...@gmail.com> wrote:
Background... c++/python programmer who sees some good things in GO but not impressed with the error handling.  I think there are often clear cut cases where some code doesn't want the burden of checking and re-raising errors, and some that do.  The some that do would be top level functions and data structures needing to keep internal state clean.  The some that definitely don't would be short scripts.

However I vaguely agree (or am neutral) on the issue of exception catching syntax being ugly control flow.  

My idea is function calls can have attributes.  I can either do:

# If error, raise an exception and someone else will handle it or not
buffer := socket.recv(100) 
file.close()

or:

# Obj can be an exception object or nil.  Control flow is guaranteed
buffer, obj :=  socket.recv(100) _catch    
obj = file.close() _catch

or perhaps this instead would be more syntax legal:

buffer, obj := catch(socket.recv(100))
obj = catch(file.close())

or even one more idea:

buffer, obj = socket.__recv(100)
obj = file.__close()

(its the same method, the leading __ just turns it into the catch version).

obj can then be inspected with normal code constructs.  catch() or _catch would make the last variable in the assignment list be the caught exception, or nil if no exception happened.

I also think it would be cool if a code editor could automatically highlight all function calls that could have a non-local return (i.e. could raise an exception).  Why make the programmer state in code / annotations what the compiler already knows?   So one could audit a function with a lot of 'red' text vs a function with a lot of 'green' (does not raise exception).  

Just my two cents.

- Karl

André Moraes

unread,
Jun 28, 2012, 9:05:01 PM6/28/12
to golang-nuts
On Thu, Jun 28, 2012 at 9:39 PM, Patrick Mylund Nielsen
<pat...@patrickmylund.com> wrote:
> I think you'll come to like this quite quickly if you write a few
> applications in Go. If err != nil {...} can get a little verbose, but I find
> it results in more robust applications. When functions let errors "bubble
> up", they do so explicitly. I initially had the same impression as you, but
> have come to love it.

Just to add to this, you don't need to use errors every where in
"your" code, the idea is that: public function should never panic and
an error parameter should be used instead.

But inside your library, ie, non-exported functions you can
panic/recover reducing much of the "if err != nil" code.

Take a look at this:
http://play.golang.org/p/4g428Yxuc5

--
André Moraes
http://amoraes.info

Stephen Day

unread,
Jun 29, 2012, 1:11:22 AM6/29/12
to golan...@googlegroups.com
I don't actually recommend doing this, but it's possible to cast two valued functions with an error into a single valued function, with a type assertion. This will ensure that you're not ignoring errors while still allowing you to be lazy about handling errors.

Here's an example:

http://play.golang.org/p/KQRqHjOSb5

You could also do the reverse and cast panics to errors.

However, as was mentioned, you're code will be way more robust if you check and handle errors as close to their source as possible and propagate them explicitly.

Ian Lance Taylor

unread,
Jun 29, 2012, 3:41:50 PM6/29/12
to karl.p...@gmail.com, golan...@googlegroups.com
On Thu, Jun 28, 2012 at 4:33 PM, <karl.p...@gmail.com> wrote:
>
> My idea is function calls can have attributes.  I can either do:
>
> # If error, raise an exception and someone else will handle it or not
> buffer := socket.recv(100)
> file.close()
>
> or:
>
> # Obj can be an exception object or nil.  Control flow is guaranteed
> buffer, obj :=  socket.recv(100) _catch
> obj = file.close() _catch
>
> or perhaps this instead would be more syntax legal:
>
> buffer, obj := catch(socket.recv(100))
> obj = catch(file.close())
>
> or even one more idea:
>
> buffer, obj = socket.__recv(100)
> obj = file.__close()
>
> (its the same method, the leading __ just turns it into the catch version).

If you really can't bear to use idiomatic Go error handling, just use
panic and recover. There is no need to introduce new syntax or new
concepts.

Ian
Reply all
Reply to author
Forward
0 new messages