Re: [go-nuts] Go Error Handling Sucks

7,089 views
Skip to first unread message

Aram Hăvărneanu

unread,
Sep 24, 2012, 2:04:55 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com
.-'\
.-' `/\
.-' `/\
\ `/\
\ `/\
\ _- `/\ _.--.
\ _- `/`-..--\ )
\ _- `,',' / ,')
`-_ - ` -- ~ ,','
`- ,','
\,--. ____==-~
\ \_-~\
`_-~_.-'
\-~

--
Aram Hăvărneanu

Dave Cheney

unread,
Sep 24, 2012, 2:06:21 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com

Hello,

If we are trading links, allow me to quote myself. 

http://dave.cheney.net/2012/01/18/why-go-gets-exceptions-right

I hope you do not dismiss Go so quickly. If you spend some time using the language, rather than being lead around by the great unwashed on reddit, you may have an opportunity to change your mind.

Dave

On 25 Sep 2012 03:59, <knotw...@gmail.com> wrote:

Its a shame that such a fantastic language is missing a better way to deal with errors. 
Exceptions might not be perfect, but are damn better than checking each and every function call.

Or am I missing something?

I just read a pair of posts that expresses these ideas much better than what I could here.



As one of the comments I read said: 99% of the time I need to code the happy path and if something breaks in the middle the error handling is exactly the same: log the error, close resources, send the caller an error code or message, end of the story.  I don't want to check every freaking single function invocation for errors.
Its a shame, I really wanted to use go.

--
 
 

Jan Mercl

unread,
Sep 24, 2012, 2:09:31 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com
On Mon, Sep 24, 2012 at 5:55 PM, <knotw...@gmail.com> wrote:
> message, end of the story. I don't want to check every freaking single
> function invocation for errors.

Most programmers don't want to. No wonder so much code fails so often.

> Its a shame, I really wanted to use go.

You might like Go if you give it a try.

-j

Patrick Mylund Nielsen

unread,
Sep 24, 2012, 2:10:02 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com
Go has exceptions (panic/recover) if you insist on doing it that way. Just don't expose the users of your APIs to un-exceptional panics (panics stemming from things other than bad input/incorrect use.)

As others mentioned, you need to use Go. Saying "It's a shame, I really wanted to use Go" without ever even touching Go is just cheating yourself out of using a great language.

On Mon, Sep 24, 2012 at 10:55 AM, <knotw...@gmail.com> wrote:

Its a shame that such a fantastic language is missing a better way to deal with errors. 
Exceptions might not be perfect, but are damn better than checking each and every function call.

Or am I missing something?

I just read a pair of posts that expresses these ideas much better than what I could here.



As one of the comments I read said: 99% of the time I need to code the happy path and if something breaks in the middle the error handling is exactly the same: log the error, close resources, send the caller an error code or message, end of the story.  I don't want to check every freaking single function invocation for errors.
Its a shame, I really wanted to use go.

--
 
 

Archos

unread,
Sep 24, 2012, 2:16:34 PM9/24/12
to golan...@googlegroups.com
The language I used before of Go was Python, so the error handling in Go was very strange for me at the beginning. In fact, one of the errors that I have done in one of my first projects was to avoid its usage on the first version, because when I started to extend that project I got errors that I didn't know where they came from.

So, my rule is always to handle errors since it does not hurts but does very robust the software.
By the way, now I want not know anymore about Python, Ruby, C++

Steven Rice

unread,
Sep 24, 2012, 2:18:45 PM9/24/12
to golan...@googlegroups.com, knotw...@gmail.com
On the contrary, Go error handling is amazing. It actually is built originally to have programmers code responsibly but now panic and recover have been added for those who wish to do things quick and messily.

Rémy Oudompheng

unread,
Sep 24, 2012, 2:22:31 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com
On 2012/9/24 <knotw...@gmail.com> wrote:
>
> Its a shame that such a fantastic language is missing a better way to deal
> with errors.
> Exceptions might not be perfect, but are damn better than checking each and
> every function call.
>
> Or am I missing something?
>
> I just read a pair of posts that expresses these ideas much better than what
> I could here.
>
> http://uberpython.wordpress.com/2012/09/23/why-im-not-leaving-python-for-go/
>
> http://www.yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html
>
> As one of the comments I read said: 99% of the time I need to code the happy
> path and if something breaks in the middle the error handling is exactly the
> same: log the error, close resources, send the caller an error code or
> message, end of the story. I don't want to check every freaking single
> function invocation for errors.
> Its a shame, I really wanted to use go.

This is a very common misconception which I think should enter the FAQ
or be the subject of a blog article integrated with the Go
documentation.

* "Go error handling sucks" is an inaccurate judgement. Error handling
is not done by Go but written by you.
If your error handling is ugly (which may happen), there are various
things you can do to help that.

* Have your functions return less errors. Errors happen when your
validate external input or perform I/O with other systems. Internal
computations should not generate errors unless you are misusing the
type system (e.g. passing potentially invalid
strings/interface/map[string]interface everywhere instead of
structured data), or in need of pre/post-conditions that cannot be
expressed in Go's type systems (then if the error is a programming
error, it is common to panic rather than return an error).

* Use higher level functions. If you call 42 functions in a row and
check errors 42 times, yes the code is repetitive and ugly, but it's
not because Go is badly conceived. It's either because you have
unrolled operations that could have been gathered in more friendly
ways, either because the operation is genuinely complicated, in which
case a careful handling of errors is needed.

* Errors are messages. They are not stack traces, they are not
stringified exception contents taken out of their context. A 50-line
Java stacktrace is not something you can show to an end-user. If you
don't care about the user and prefer raw stacktraces, it might be
because you are scripting. Then you can use panic in Go or Python,
because you don't want to bother about proper error handling.
Identifying the location of an error, its root cause or its context
requires human interaction or a powerful natural language algorithm.
When you talk to human beings (I mean, not programmers), replacing a
stack trace by a helpful sentence that help both end user and
programmer for bug reports is a delicate art. Requiring users to run a
gdb session is not an option.

Websites errors that say "We have encountered an error, sorry for your
request" because stack traces are "security breaches" (that's what
they think at Django's, I've heard), are unhelpful ("yes, I clearly
see you have a problem") and disrespectful to the end-user.

Rémy.

Gustavo Niemeyer

unread,
Sep 24, 2012, 2:35:33 PM9/24/12
to Aram Hăvărneanu, knotw...@gmail.com, golan...@googlegroups.com
FWIW, I find that unnecessarily unfriendly. This is a pretty common
issue people perceive when coming to the language, and it's to me one
of the great benefits of Go too. This is a user mailing list, so I
suggest we try to welcome people with those kinds of questions with
proper feedback, as done by others here, rather incorrectly suggesting
no one cares.

To the OP, if you're considering Python vs. Go, here are a handful of
posts to get you thinking.

Curiously, many of them were written before I switched to Go.

http://blog.labix.org/2009/05/15/class-member-access-control-enforcement-vs-convention
http://blog.labix.org/2009/07/02/screwing-up-python-compatibility-unicode-str-bytes
http://blog.labix.org/2010/06/17/the-forgotten-art-of-error-checking
http://blog.labix.org/2010/07/09/python-has-a-gil-and-lots-of-complainers
http://blog.labix.org/2010/11/09/interfaces-and-the-design-of-software
http://blog.labix.org/2011/12/12/good-concurrency-changes-the-game
http://blog.labix.org/2012/06/26/less-is-more-and-is-not-always-straightforward
> --
>
>



--

gustavo @ http://niemeyer.net

Steven Johnson

unread,
Sep 24, 2012, 3:05:24 PM9/24/12
to golan...@googlegroups.com
On Mon, Sep 24, 2012 at 8:55 AM, <knotw...@gmail.com> wrote:
>
> Its a shame that such a fantastic language is missing a better way to deal with errors.
> Exceptions might not be perfect, but are damn better than checking each and every function call.

There's no accounting for taste, I guess -- IMHO the Go error checking
style is one of the things I find to be a big benefit of the language.
There's no hidden control flow; error conditions are in your face and
you have to make a deliberate decision to ignore them (thanks to the
no-warning, no-unused-declarations compiler).

(OK, technically panic/recover are "hidden control flow", but they're
really only for use after the ship has already hit the iceberg, so to
speak...)

Andrew Gerrand

unread,
Sep 24, 2012, 3:27:01 PM9/24/12
to Gustavo Niemeyer, Aram Hăvărneanu, knotw...@gmail.com, golan...@googlegroups.com
There is some discussion of error handling in this talk, Go in Production:
http://www.youtube.com/watch?v=kKQLhGZVN4A

Andrew

DisposaBoy

unread,
Sep 24, 2012, 3:47:22 PM9/24/12
to golan...@googlegroups.com, knotw...@gmail.com


On Monday, September 24, 2012 4:55:57 PM UTC+1, (unknown) wrote:

Its a shame that such a fantastic language is missing a better way to deal with errors. 
Exceptions might not be perfect, but are damn better than checking each and every function call.

Or am I missing something?

I just read a pair of posts that expresses these ideas much better than what I could here.



As one of the comments I read said: 99% of the time I need to code the happy path and if something breaks in the middle the error handling is exactly the same: log the error, close resources, send the caller an error code or message, end of the story.  I don't want to check every freaking single function invocation for errors.
Its a shame, I really wanted to use go.


Form what you've said, it doesn't appear that you are able to form your own opinions. What happens if I tell you that it's a good idea to go jumping off bridges? ... In any case, please don't spam the list


 

bryanturley

unread,
Sep 24, 2012, 4:04:08 PM9/24/12
to golan...@googlegroups.com, knotw...@gmail.com
Beyond what everyone else has said already...
Just because something returns an error doesn't mean you have to check it.
Though you will probably wish you had at some point a day or 2 after whatever your working on mysteriously stops though ;)

Rémy Oudompheng

unread,
Sep 24, 2012, 4:52:07 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com
On 2012/9/24 <knotw...@gmail.com> wrote:
> @bryanturley Well, thats exactly the problem. If you fail to check it and
> something breaks in 2 days, you won't have a clue of what happened. With
> exceptions, you will know exactly what happened and exactly where and when.

Again, this is a programmer point of view. A user (programmer or not)
doesn't know much more about the problem when presented a stack trace.
In many programming styles, exceptions that are caught forget where
they happened (because the ugly stack trace is discarded) an when they
happened (such information is seldom recorded). In some situations
where you want to conceal the source code, you even don't want to show
it.

Rémy.

Gustavo Niemeyer

unread,
Sep 24, 2012, 5:17:21 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com
On Mon, Sep 24, 2012 at 5:52 PM, <knotw...@gmail.com> wrote:
> @Dave Cheney Good article explaining the pros/cons of each .... but still
> unconvinced. I'm still partial to un-checked exceptions despite the issues
> that you point out.

I think people are eagerly trying to show you a different perspective,
rather than simply attempting to convince you of anything. I
appreciate the conventions in Go because I have to write software that
doesn't crash, even when I'm not looking, not because someone tried to
convince me.


gustavo @ http://niemeyer.net

Harley Laue

unread,
Sep 24, 2012, 6:06:24 PM9/24/12
to golan...@googlegroups.com, knotw...@gmail.com
Well, in C++ take the following code:
#include <stdexcept>
#include <iostream>
#include <cstdlib>

void C() {
throw std::runtime_error("Let someone else deal with it");
}

void B() {
C();
throw std::runtime_error("Let someone else deal with it");
}

void A() {
try {
B();
}
// A not to uncommon exception catch-all
catch(std::exception &e) {
std::cout << "Unacceptable error: " << e.what() << std::endl;
throw;
}
}

int main(int argc, char *argv[]) {
A();
}

With this simple example, it's pretty easy to see where the exception
is being thrown, but add 50+ lines of code and things become less
clear that B was lazy and just let A deal with C's exception. The
stack trace is going to lead you to A, but from there, you'll have to
hunt as to what actually threw the error because B didn't handle C's
exception when it called it because "it's someone elses problem." This
type of situation actually comes up more frequently than it should.

*shrugs* It's really up to you though to give it a try, decide if you
like Go's method or not. As others have said, it does tend to cause
programs to have less issues because errors are either dealt with, or
they were ignored leading to issues down the road.

On Mon, Sep 24, 2012 at 3:52 PM, <knotw...@gmail.com> wrote:
>
> @Dave Cheney Good article explaining the pros/cons of each .... but still
> unconvinced. I'm still partial to un-checked exceptions despite the issues
> that you point out.
>
>
> --
>
>

Patrick Mylund Nielsen

unread,
Sep 24, 2012, 6:45:59 PM9/24/12
to Rémy Oudompheng, knotw...@gmail.com, golan...@googlegroups.com
100% agree with your first four points.

Websites errors that say "We have encountered an error, sorry for your request" because stack traces are "security breaches" (that's what they think at Django's, I've heard), are unhelpful ("yes, I clearly see you have a problem") and disrespectful to the end-user.

They DO pose security concerns, and to comment on your specific example, Django includes much, much more than just a stack trace in its development mode exception view (like file paths and other configuration options.) I don't know if "at Django's" is supposed to be an insult, but this is a pretty fundamental rule in cryptography: don't reveal internal state on errors, and especially don't try to continue the session; just cut the connection/session.

There is no reason that you shouldn't tell your user what field of a form they entered incorrectly, but there also isn't any reason whatsoever that you should dump e.g. a web application's state to the page when an unexpected error is encountered. I think you are arguing against yourself a bit here: as you said, 99% of users don't care about, or won't read your stack traces, so why should you give them one if they encounter an unknown error on your site?

net/http handles this correctly: a panic in a request goroutine aborts a response, and the panic is recovered, letting the http server continue. If you handle error return values, you have an opportunity to render the error message nicely, assuming that that error is one you want to show (probably don't want an "Failed to connect to PostgreSQL database; connection string "user=foo password=bar..." output on the page.

There's no reason you can't do the same in Django, it's just a lot harder since handling a lot of different possible exceptions and adding descriptions for them is much clumsier, like you describe.


Rémy.

--



Rémy Oudompheng

unread,
Sep 24, 2012, 7:12:36 PM9/24/12
to Patrick Mylund Nielsen, knotw...@gmail.com, golan...@googlegroups.com
On 2012/9/25 Patrick Mylund Nielsen <pat...@patrickmylund.com> wrote:
> They DO pose security concerns, and to comment on your specific example,
> Django includes much, much more than just a stack trace in its development
> mode exception view (like file paths and other configuration options.) I
> don't know if "at Django's" is supposed to be an insult, but this is a
> pretty fundamental rule in cryptography: don't reveal internal state on
> errors, and especially don't try to continue the session; just cut the
> connection/session.
>
> There is no reason that you shouldn't tell your user what field of a form
> they entered incorrectly, but there also isn't any reason whatsoever that
> you should dump e.g. a web application's state to the page when an
> unexpected error is encountered. I think you are arguing against yourself a
> bit here: as you said, 99% of users don't care about, or won't read your
> stack traces, so why should you give them one if they encounter an unknown
> error on your site?

My point was that, in languages that encourage you to use exceptions,
when an exception occur that is not handled (due to an overlook or
whatever), the framework doesn't have anything else than a stack trace
or internal state to describe the error, and since there is nothing
interesting to do, it doesn't show a useful error.

This doesn't happen in languages that encourage you to check all errors.

Rémy.

Patrick Mylund Nielsen

unread,
Sep 24, 2012, 7:14:16 PM9/24/12
to Rémy Oudompheng, knotw...@gmail.com, golan...@googlegroups.com
Ah, then I agree :) Nothing to see here.

Patrick Mylund Nielsen

unread,
Sep 24, 2012, 7:52:01 PM9/24/12
to knotw...@gmail.com, golan...@googlegroups.com
What DisposaBoy was pointing out is that your original post basically read, "Your error handling sucks! Some other guys said that your error handling sucks. Why does it suck? Too bad, now I won't use your language", and it was obvious that you haven't actually used the language yourself. You need to use the language, or at least study (more) code written in it, before you adopt and parrot somebody else's opinion, especially if you're going to post such a condescending/derisive message to that language's mailing list.

Of course, that doesn't just apply to programming languages. Many programmers use NoSQL databases to be able to make "web scale" applications, and not RDBMS, even though they will likely be tens or hundreds of times as productive using something relational, and won't actually have the problems that Facebook has for messaging (they still use MySQL for everything else)--and one of the major reasons they're using these solutions is that Hacker News and reddit.com/r/programming are filled with threads that worship the latest new thing and dismisses RDBMSs as "old and bad" (when in reality they're some of the most mature pieces of software that exist.) Now that Google has unveiled Spanner, maybe all the programmers who made MongoDB applications will rave about ACID, transactional consistency and the ease-of-use of query languages... :) (It already exists I guess: "NewSQL".)

My/our point is: Don't dismiss something because someone got to #1 on Hacker News criticizing it. In a lot of cases, they don't really know what they're talking about, so adopting their (misinformed) opinion is doing yourself a disfavor. NoSQL, or exceptions, may be right for you, but that may be the case far less often than you'd think if you ingest Hacker News articles uncritically. Try it, then make up your own mind.


On Mon, Sep 24, 2012 at 6:35 PM, <knotw...@gmail.com> wrote:
@DisposaBoy I do have my opinions, I just pointed to a blog that summed it up quite nicely. If you tell me to jump of a bridge, I will probably push you off instead. You are the one spamming the list with your reply devoid of content.  As you can see, there has been quite some interest in my sololoquy.
--
 
 

Michael Jones

unread,
Sep 24, 2012, 8:51:26 PM9/24/12
to Patrick Mylund Nielsen, knotw...@gmail.com, golan...@googlegroups.com
One positive point about exceptions: it is nice to have the "happy case" code flow be clean. I perform a mental code folding around the expected outcomes when reading. Sometimes my inability to do this influences my design so that it can work out that way. In a perfect world it would be great to have both:

* Error handling right at the point of return so that you can see what is handled or not handled, how it is handled, and what types of failures are possible.

* Error handling somewhere else so that the logic of the algorithm is expressed purely and not obscured by a crowd of real-world constraints and possibile woes.

Clearly a compromise is to be expected and as Dave Cheney's article explains, the issue is about where and how to implement out-of-band signaling. There are only so many choices and most of them have been tried by a number of programming languages. (Though some may not be familiar with many of those explorations.) There may be new ways, but if the choice is between too mysterious and too explicit then I prefer Go's explicit handling at the point of return (which is also the point of call in most languages ;-)

If I can have new and possibly complicated language features, I might be tempted to support something that helps with information hiding in cases where the error handling feels redundant and bulky compared to the underlying code.

One wonderful example of this kind of outcome is Go's defer, which factors the proper handling of cases out of each leaf of the code path. Imagine an error handling version along similar lines. I'll describe it here not as a proposal, but as an unpolished but hopefully clear way to make my meaning plain.

Imagine a magic kind of active variable where assigning non-zero to it stored a value and also (hold your booing) caused an implicit goto. Now, imagine that we used such a mechanism to implement something like this:

:
resultA, active := functionA( ... )
:
resultB, active := functionB( ... )
:

handle active {
case memoryError:
    :
case diskExploded:
    :
case alienInvasion:
    Panic
 }

This kind of thing (just a quick example at 5am in a hotel in Delhi, be gentle with me) would allow one to "hide" the handling somewhere else when useful, would let developers factor a number of "out of same resource and share the same action" cases with one block of handling code, and do much of what exceptions do magically via the stack in a visible way using the multiple return value and a jump based on assigned data. In practice, the active variable could just be named "handle" and the handle kind of switch could use the implicit handle value. They could nest, maybe, or have labels or whatnot. My point is not to suggest how to do it but to share that there are virtues in exceptions that have nothing to do with the actual exception mechanism, how they work in other languages, how they have been cruelly overused, and so on.

Michael

P.S. knotwelkum, your observations are welcome by me.

--
 
 



--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

Patrick Mylund Nielsen

unread,
Sep 24, 2012, 9:15:05 PM9/24/12
to Michael Jones, knotw...@gmail.com, golan...@googlegroups.com
FWIW I didn't mean to imply that exceptions are bad--perhaps the comparison to NoSQL hype was unfair :)--just that error return values aren't. The code may be harder to skim (although I think it's something you get used to), but it leads to code that is more "naturally" robust, and, as a side effect, error messages that are much more specific (as Remy mentioned.)

Look at a language like Haskell: they have the Maybe and Either data types--Maybe a is a value that may be Just a or Nothing, and Either a b is a value that may be Left a (where a is usually an error type) or Right b (where b is some thing), but they also have Python-esque exceptions. Sound familiar? (On that note, Haskell actually has several more ways to do error handling, and they've been debating how to solve that so as to not have varying error handling techniques across packages (which means package authors can't anticipate what kinds of errors they need to handle)--http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors / http://article.gmane.org/gmane.comp.lang.haskell.libraries/6382. Go strikes a nice balance, IMO, between Either and "awkward exceptions" (panic/recover.)

Peter

unread,
Sep 25, 2012, 6:52:45 AM9/25/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
Do you mean something like:

f, panic := os.Create("filename")

where assigning a non-nil value to panic would cause it to panic?

Some kind of generalised version of this where you could do an implicit != nil check might make for cleaner code, but I worry about the *extra* "mental code folding" needed to really understand something like that.

Michael Jones

unread,
Sep 25, 2012, 8:25:18 AM9/25/12
to Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
Yes, broadly. and yes, hiding actions in an implicit behavior is both good and bad for the reasons you say. And, as I wrote, this was just an example (implicit branches/actions based triggered by value assigned) of the idea that there is something nice about separating the out-of-band handling of special case circumstances. 

I'm a fan of the belief underlying Donald Knuth's WEB (weave/tangle) system that presentation to the reader is part (perhaps most in some cases) of the beauty and art of programming. Hiding/Showing is part of this. Together/Separate can be part of this. In the literal example of WEB, Knuth uses trivial macros to do much of his hiding. (Not making a case for WEB, just pointing out that lightweight, inline macros are another way people have tried to have it both ways.)

Ian Lance Taylor

unread,
Sep 25, 2012, 8:43:30 AM9/25/12
to Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
On Tue, Sep 25, 2012 at 3:52 AM, Peter <peter.a...@gmail.com> wrote:
> Do you mean something like:
>
> f, panic := os.Create("filename")
>
> where assigning a non-nil value to panic would cause it to panic?

That's kind of interesting. I don't see quite how to make it work
with panic, but I see how it could work with return, which is a
keyword. One could say that
f, return = os.Create("filename")
was permitted if 1) the function being called returns a parameter of
the builtin type error at the point the return keyword is used; 2) the
function making the call returns a single parameter of the builtin
type error. It would mean: if the value assigned to the "return"
keyword is non-nil, then the calling function immediately returns,
with that value as the error result, and with the other results
holding whatever value they hold at that point (if the results are
unnamed, zero).

Magic syntactic sugar, yes, but not too hard to understand. Might be
overused, though, and doesn't help with the problem of ignoring the
result entirely, e.g., of f.Close().

Ian

Gustavo Niemeyer

unread,
Sep 25, 2012, 9:08:57 AM9/25/12
to Michael Jones, Patrick Mylund Nielsen, knotw...@gmail.com, golan...@googlegroups.com
On Mon, Sep 24, 2012 at 9:51 PM, Michael Jones <m...@google.com> wrote:
> One positive point about exceptions: it is nice to have the "happy case"
> code flow be clean.
(...)
> * Error handling somewhere else so that the logic of the algorithm is
> expressed purely and not obscured by a crowd of real-world constraints and
> possibile woes.

The happy case is when the code does what it should. Just because one
wants something to not happen doesn't make it less true nor less
important. It is very much part of the algorithm.

We have been teaching people otherwise for such a long time. No wonder
most software is so unstable.


gustavo @ http://niemeyer.net

Jan Mercl

unread,
Sep 25, 2012, 9:12:56 AM9/25/12
to Ian Lance Taylor, Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
On Tue, Sep 25, 2012 at 2:43 PM, Ian Lance Taylor <ia...@google.com> wrote:
> On Tue, Sep 25, 2012 at 3:52 AM, Peter <peter.a...@gmail.com> wrote:
> That's kind of interesting. I don't see quite how to make it work
> with panic, but I see how it could work with return, which is a
> keyword. One could say that
> f, return = os.Create("filename")
> was permitted if 1) the function being called returns a parameter of
> the builtin type error at the point the return keyword is used; 2) the
> function making the call returns a single parameter of the builtin
> type error. It would mean: if the value assigned to the "return"
> keyword is non-nil, then the calling function immediately returns,
> with that value as the error result, and with the other results
> holding whatever value they hold at that point (if the results are
> unnamed, zero).

That would make for a (sometimes) big SLOC reduction, so I kinda like
it. But the newly introduced invisibility of 'if err != nil' is IMO a
cost too big to afford comfortably.

-j

Michael Jones

unread,
Sep 25, 2012, 9:50:40 AM9/25/12
to Ian Lance Taylor, Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
I had imagined also being able to get to a switch statement via this mechanism. That lets common handling be centralized. (shown in first email) But the key mechanism is that non-nil / non-zero assignment means "take an action"


Ian

--


yy

unread,
Sep 25, 2012, 10:09:09 AM9/25/12
to Michael Jones, Ian Lance Taylor, Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
On 25 September 2012 15:50, Michael Jones <m...@google.com> wrote:
> I had imagined also being able to get to a switch statement via this
> mechanism. That lets common handling be centralized. (shown in first email)
> But the key mechanism is that non-nil / non-zero assignment means "take an
> action"

You could use defer:

defer func() {
switch err { // assume err is the name of the return value
case memoryError:
:
case diskExploded:
:
case alienInvasion:
Panic
}
}()

:
resultA, return := functionA( ... )
:
resultB, return := functionB( ... )
:

I preferred your original solution (if we are adding sugar, let's make
it as sweet as possible), but I'm not completely sure about all this.
However, it looks like an interesting idea and, well matured, it may
be a good candidate for a future (long term future) version of the
language.


--
- yiyus || JGL .

Jakub Labath

unread,
Sep 25, 2012, 10:30:04 AM9/25/12
to golan...@googlegroups.com
Exactly you say. Funny I do not see that in actual production code. As someone who makes a living maintaining old software I see a lot of this.

try:
...30+ lines...
catch Exception as e:
  print "Error occured", e
 
Yes they could print a stack trace in there but most "geniuses" never do. So when the error is something like ValueError or IOError or NullPointer. It's basically as useful as assigning all your go errors to _.
Actually it's even worse because when I see _ I know that i need to go in and replace it with error handling. When I just see bunch of code I have no idea which of the calls can throw an error.


| Exceptions might not be perfect, but are damn better than checking each and every function call.

So my above example could be written like this in go,

func monsterFunction() (result string, err error){
   if err = smallCallThatCanFail1(); err != nil {
      return
   }
   if err = smallCallThatCanFail2(); err != nil {
      return
   }
  .... and so on
   result = "ALL OK"
   return
}

And then deal with the error returned in the caller of the monsterFunction. Is it more lines than an exception yes. But well worth the tradeoff in how much more obvious it is to tell in go code what is going on.

Final thought when writing robust software I check every function that can fail regardless of whether I use java, python or go. It slows you done initially but it pays off big time much later.

In my opinion the go's error handling is one of the finest that I know.

Cheers



On Monday, September 24, 2012 4:42:58 PM UTC-4, (unknown) wrote:
@bryanturley Well, thats exactly the problem.  If you fail to check it and something breaks in 2 days, you won't have a clue of what happened. With exceptions, you will know exactly what happened and exactly where and when.

ISockGo

unread,
Sep 25, 2012, 10:57:55 AM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
Hello Mr Unknown :),

                            Go is a wonderful language. Every language has it's own style and behavior, the bigest challenge for a languages is to keep the memory and CPU down and provide the easy way to code it. Go came up with a new way of writing code and using the OOPs, with the power of C and code style like python. And the best part it gives you an executable output which does not require any run time or virtual machine environment to run the programme on different type of OS. The traditional OOPs and try-catch methodologies are very memory consuming, specially when programers don't know how to code it better and where to use what. The most Java programs are memory consuming, you can check.

I think, that is the reason, Go came up with this old error handling management. 

Keep rocking Goians :)


Thanks,
Chuck  

Nguyên Nguyễn Văn Cao

unread,
Sep 25, 2012, 11:06:04 AM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
I'm not a professional programmer, the fact that I was a student.
All the benefits I found was that when you use exceptions you do not need to declare an extra output parameter to handle errors. And in my point of view, there is no big difference.
Here is how my teacher show me how to use exception:
try {
MaybeAnIssue();
} catch {
//do something else or safety quit
}
with Go:
err :=  MaybeAnIssue()
if err != nil {
//do something else or safety quit 
}

So in Go way, we write some more code, but the idea is the same, is it right?
Or with exception we don't need to check the if there is throwed exception?
Vào 22:55:57 UTC+7 Thứ hai, ngày 24 tháng chín năm 2012, (không xác định) đã viết:

Peter

unread,
Sep 25, 2012, 11:41:48 AM9/25/12
to golan...@googlegroups.com, Ian Lance Taylor, Peter, Patrick Mylund Nielsen, knotw...@gmail.com
This is an interesting idea Michael, thanks.

IMO,
if I am writing production code I don't mind the errors being handled explicitly and simply, even if a little verbosely.
However when writing prototype code I would like a way to handle errors without confusing debugging, i.e. I'd like to code
for the working case and patch up errors as I find them, but without spending effort tracking them down.
Some sugar that makes all errors fatal (by panicking with a trace) would provide some support, but I'm not sure that would handle ignored errors,
especially ones from fmt.Println, etc, which I want to implicitly ignore.

The amount of error handling in Go makes me appreciate how much other languages ignore them. In the same way that I worry about 
making a typo in a variable name if coding in Javascript, I am also suddenly aware of a variety of failure modes.

Ian Lance Taylor

unread,
Sep 25, 2012, 11:43:15 AM9/25/12
to Michael Jones, Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
On Tue, Sep 25, 2012 at 6:50 AM, Michael Jones <m...@google.com> wrote:
> I had imagined also being able to get to a switch statement via this
> mechanism. That lets common handling be centralized. (shown in first email)
> But the key mechanism is that non-nil / non-zero assignment means "take an
> action"

Yeah, my idea is laughably non-general. But here is a different idea,
that is more like yours: let labels be variables. A read from a label
is just an ordinary read. When writing to a label, though, if the
value is non-zero, the program does a goto the label.

Then we can write

func F(filename string) error {
f, err := os.Open(filename)
_, err = f.Write("hi")
err = f.Close()
fmt.Println("done")
return nil
err:
return err
}

And since I can't let well enough alone, let's permit this same idea
with the special label "return", where of course it is only meaningful
to use the label name as a result parameter.

func F(filename string) (return error) {
f, return := os.Open(filename)
_, return = f.Write("hi")
return = f.Close()
fmt.Println("done")
return nil
}

No special handling of the error type, very little additional syntax
(permit the return keyword in a couple more places, and permit an
optional type on the label declaration so we can write "foo
interface{}:").

Ian

Lucio

unread,
Sep 25, 2012, 12:04:49 PM9/25/12
to golan...@googlegroups.com, Peter, Patrick Mylund Nielsen, knotw...@gmail.com
We want two things here: the alert (exception) and the return value, with options to declare either
or both, well, optional.  This smacks of "channel" to me, where the appearance of a value triggers
further processing.  The Tcl notion of a catch wrapper also contributes to the concept, so that we
would have a "catch" invocation which would pass the "error" result value to a channel receiver,
the latter being the exception handler.  Does it make any sense?

Given the existing Go structure, we could do it with a special "catch" wrapper for each function type,
but a general "catch" wrapper would provide the useful syntactic sugar.  Not unlike the "go" prefix,
actually, in principle, except that we somehow have to specify the target function.

Let me see

catch n, err := b.Read(buf); except <- err

...sort of thing?

I don't quite like it, but this is what I want to put on the table for further discussion.

Lucio.

Larry Clapp

unread,
Sep 25, 2012, 12:10:09 PM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
It's funny.  When I heard about Go, I went to golang.org and read through the tour, and then went through it again and coded a lot of the problems in it.  And you know what: I decided I like Go.  How did you form your opinion about it?  Tangentially, how much Go have you written?

If you don't like Go, great.  More power to you.  What was your motivation for telling us so, and (in my opinion) so rudely, at that?  Why should we respond with anything more than a crisp, clear, "fuck you too"?

-- Larry


On Monday, September 24, 2012 11:55:57 AM UTC-4, (unknown) wrote:

Daniel Morsing

unread,
Sep 25, 2012, 12:20:50 PM9/25/12
to Ian Lance Taylor, Michael Jones, Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
On Tue, Sep 25, 2012 at 5:43 PM, Ian Lance Taylor <ia...@google.com> wrote:
>
> func F(filename string) error {
> f, err := os.Open(filename)
> _, err = f.Write("hi")
> err = f.Close()
> fmt.Println("done")
> return nil
> err:
> return err
> }
>

I really don't like this. Seemingly unrelated actions that have
non-local effects would be a bad idea to introduce to go. It has
problems when you have a 3 screen long function where you cannot see
the label when you first start reading it.

It also breaks go1 compatibility since labels can be the same name as
variables right now.

The other ideas are promising. A bit too magical for my tastes but I
think they could be made less magical through the use of a good syntax
(Which I'm not going to start bikeshedding right now).

Steven Rice

unread,
Sep 25, 2012, 12:22:58 PM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
I always enjoy your input Larry :). Also OP stated " I don't want to check every freaking single function invocation for errors. " Go actually allows you to do this, languages that throw exceptions do not. In Go the worst thing that happens if you ignore an error is unexpected behavior. In exception throwing languages, if you ignore the exception then your program crashes.

Larry Clapp

unread,
Sep 25, 2012, 12:51:07 PM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
Awesome.  :)

Just for the record: None of those question were rhetorical.  I'm curious about the answer to all of them.  (Which should not be interpreted to mean I demand or believe that I deserve or am owed an answer, either.  The OP may answer or not, as s/he wishes.  I'm just curious.)

-- L

Michael Jones

unread,
Sep 25, 2012, 1:33:00 PM9/25/12
to Ian Lance Taylor, Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
I like it. Looks clean and clear (at least, once one accepts the magic implicit jump.)

Now, let's get in the Wayback machine and have a look at what came before. 
Donald Knuth wrote "Structured Programming with Go To Statements" in 1974.

    Knuth, "Structured Programming with Go To Statements"

That paper is a survey on being general, efficient, and retaining clarity. One of the
gems in that paper is something I mentioned here recently, Charles Zahn's event
indicators. In the paper Knuth suggests a parameterized extension of them. Our
thinking here is a minimalist reduction of their key point, implemented in a more
general framework. The ideas are close enough that  Zahn's construction with
Knuth's extension offers us some guidance. Indeed, all that Knuth writes in the 
paper deserves the closest study in connection with this discussion, as does 
Zahn's paper and his notion of "conceptual distance."

    Zahn, "Structured Control in Programming Languages"

I like our scheme better, but acknowledge and respect all that comes before. If you
read the above and think about the meaning more than the literal, then you'll see that 
assignment in our magic action variables/labels has the power of Knuth's parameter 
extension to Zahn's idea, the name of the label/variable pays the role of the
event indicator, and the magic jump on non-zero assignment is the new wrinkle
that adds either confusion or clarity depending on your point of view. ;-)

Patrick Mylund Nielsen

unread,
Sep 25, 2012, 2:08:40 PM9/25/12
to knotw...@gmail.com, golan...@googlegroups.com
> I made this post while fiddling with a piece of code that dind't do anything. Nothing got printed, no error reported, nada.  How on earth am I supposed to start troubleshooting the damn thing.  With exceptions, I will have a nice stacktrace that will pinpoint exactly where I messed up. 

That sounds very strange, especially since each error value will include specific information if there was an error. Can you show your code? http://play.golang.org/ -> Share

On Tue, Sep 25, 2012 at 12:40 PM, <knotw...@gmail.com> wrote:



On Tuesday, September 25, 2012 11:10:09 AM UTC-5, Larry Clapp wrote:
It's funny.  When I heard about Go, I went to golang.org and read through the tour, and then went through it again and coded a lot of the problems in it.  And you know what: I decided I like Go.  How did you form your opinion about it?  
 
I do like go.  I also read the tour and bought a book.

Tangentially, how much Go have you written?


Very, very little.  I made this post while fiddling with a piece of code that dind't do anything. Nothing got printed, no error reported, nada.  How on earth am I supposed to start troubleshooting the damn thing.  With exceptions, I will have a nice stacktrace that will pinpoint exactly where I messed up. 

If you don't like Go, great.  More power to you.  What was your motivation for telling us so, and (in my opinion) so rudely, at that?  Why should we respond with anything more than a crisp, clear, "fuck you too"?


Sorry for the rude post, I have already aknowledged that.  It was also on purpose, because I knew it would get more attention... 
 
-- Larry


On Monday, September 24, 2012 11:55:57 AM UTC-4, (unknown) wrote:

Its a shame that such a fantastic language is missing a better way to deal with errors. 
Exceptions might not be perfect, but are damn better than checking each and every function call.

Or am I missing something?

I just read a pair of posts that expresses these ideas much better than what I could here.



As one of the comments I read said: 99% of the time I need to code the happy path and if something breaks in the middle the error handling is exactly the same: log the error, close resources, send the caller an error code or message, end of the story.  I don't want to check every freaking single function invocation for errors.
Its a shame, I really wanted to use go.

--
 
 

Steven Rice

unread,
Sep 25, 2012, 2:14:23 PM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
Can only happen in a semantic error and that will be exactly the same in any language you ever use. If it is a compiler error, you will see the error. 



On Tuesday, September 25, 2012 12:40:06 PM UTC-5, (unknown) wrote:



On Tuesday, September 25, 2012 11:10:09 AM UTC-5, Larry Clapp wrote:

Tangentially, how much Go have you written?


Steven Rice

unread,
Sep 25, 2012, 2:33:40 PM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
Also as I replied to the article on keeping Python vs. Go: that article complains about lower level error handling, not Go itself. I don't think high level programming or Python are bad. In fact I rather enjoy Python. I do think however that Go handles problems that Python does not handle well and that Go can handle Pythons problem domain with better performance (Although it may not be as quick to code all the string parsing in Go)

Larry Clapp

unread,
Sep 25, 2012, 2:42:33 PM9/25/12
to golan...@googlegroups.com, knotw...@gmail.com
Well, you know, you could've just said "I'm having trouble with this code; I expect X and get Y."  Have you ever read How To Ask Questions The Smart Way?

It was also on purpose, because I knew it would get more attention... 


-- L


On Tuesday, September 25, 2012 1:40:06 PM UTC-4, (unknown) wrote:

On Tuesday, September 25, 2012 11:10:09 AM UTC-5, Larry Clapp wrote:
It's funny.  When I heard about Go, I went to golang.org and read through the tour, and then went through it again and coded a lot of the problems in it.  And you know what: I decided I like Go.  How did you form your opinion about it?  
 
I do like go.  I also read the tour and bought a book.

Tangentially, how much Go have you written?


Very, very little.  I made this post while fiddling with a piece of code that dind't do anything. Nothing got printed, no error reported, nada.  How on earth am I supposed to start troubleshooting the damn thing.  With exceptions, I will have a nice stacktrace that will pinpoint exactly where I messed up. 

If you don't like Go, great.  More power to you.  What was your motivation for telling us so, and (in my opinion) so rudely, at that?  Why should we respond with anything more than a crisp, clear, "fuck you too"?


Sorry for the rude post, I have already aknowledged that.  It was also on purpose, because I knew it would get more attention... 
 
-- Larry

Alexander Neumann

unread,
Sep 25, 2012, 2:46:43 PM9/25/12
to golan...@googlegroups.com, Michael Jones, Peter, Patrick Mylund Nielsen, knotw...@gmail.com
I like the "return" variant, not sure about the more general idea with labels. Would be nice to see something like this materialize in a not too distant version of Go.

Also reminds me of this old thread:

Ziad Hatahet

unread,
Sep 25, 2012, 3:34:59 PM9/25/12
to Steven Rice, golan...@googlegroups.com, knotw...@gmail.com
I would take a crash over unexpected/undefined behavior.

--
Ziad


--
 
 

Steven Rice

unread,
Sep 25, 2012, 3:39:30 PM9/25/12
to golan...@googlegroups.com, Steven Rice, knotw...@gmail.com
The user would rather not see either of them, so you could just check all your errors anyways. It is good programming to do so. The OP was complaining that Go forced error checking when this isn't true though.

Patrick Mylund Nielsen

unread,
Sep 25, 2012, 3:40:43 PM9/25/12
to Ziad Hatahet, Steven Rice, golan...@googlegroups.com, knotw...@gmail.com
It's unexpected behavior (to the programmer), not undefined behavior. Also, this only happens if you both ignore the returned error value, and if the other return value(s) in whatever form they were returned aren't sufficien (which is usually the case.)

So, you only get unexpected behavior if you do:

foo, _ := Foo()
// no if err != nil { ... }

that's why that's frowned upon.

(In most cases, the unexpected behavior will be a nil pointer dereference, so you do get the exception/panic and stack trace, anyway.)

--
 
 

Robert Johnstone

unread,
Sep 25, 2012, 5:50:25 PM9/25/12
to golan...@googlegroups.com
+1

Nigel Tao

unread,
Sep 25, 2012, 7:16:20 PM9/25/12
to Ian Lance Taylor, Peter, golan...@googlegroups.com, Patrick Mylund Nielsen, knotw...@gmail.com
On 25 September 2012 22:43, Ian Lance Taylor <ia...@google.com> wrote:
> One could say that
> f, return = os.Create("filename")
> was permitted

It's mostly academic at this point, but if we're brainstorming new
syntax, another (half-baked) idea is something like:

$ is an operator that can only be used inside a function (let's call
it f) that returns (ret0, ret1, ..., retN, error). Suppose g is a
function or method called inside f, and g(etc) would normally return
(a, b, err). $g(etc) would mean (a, b) if err is nil, otherwise f
returns (zero0, zero1, ..., zeroN, err).


For example:

n, err := fmt.Fprintf(w, "hello\n")
if err != nil {
return err
}

could become

n := $fmt.Fprintf(w, "hello\n")

and

func readAllZlib(r io.Reader) ([]byte, error) {
zr, err := zlib.NewReader(r)
if err != nil {
return nil, err
}
return ioutil.ReadAll(zr)
}

could become

func readAllZlib(r io.Reader) ([]byte, error) {
return ioutil.ReadAll($zlib.NewReader(r))
}


I'm not sure if I actually like the idea. It does save some
boilerplate, but it also discourages adding extra context to errors:

if err != nil {
return nil, fmt.Errorf("http: error connecting to proxy %s: %v",
cm.proxyURL, err)
}

is more useful than

if err != nil {
return nil, err
}

Zizon Qiu

unread,
Sep 26, 2012, 12:46:55 AM9/26/12
to knotw...@gmail.com, golan...@googlegroups.com
IMO,one prefer try-catch over error code could use the panic/defer/recover pattern in Go.
such that instead of the normal try-catch

try {
  doSomething();
}catch( Exception e){
  handleException(e);
}

doing like this, 

doSomething() // use panic instead of throw exception
defer catch(){
  if r := recover(); r != nil{
    // here r is the panic context,we SHOULD know which panic it exactly is.
    // and we can "resume" the control flow like the normal try-catch using necessary clause.
  }
}()

Dave Cheney

unread,
Sep 26, 2012, 2:48:06 AM9/26/12
to pablo....@gmail.com, golan...@googlegroups.com, knotw...@gmail.com
I'd afraid this example falls foul here

fmt.Println("Goodbye cruel world") // maybe should panic if whatever
os.Stdout was pointing too at the time failed to write, maybe

file.Close() // should this panic ? really ? what do you want to do if
you can't _close_ a file descriptor ?

On Wed, Sep 26, 2012 at 3:59 PM, <pablo....@gmail.com> wrote:
>
> Why not get the best of both (off the top of my head):
>
> If you assign the error to a variable, then business as usual (the Go way),
> e.g.:
>
> if err := sealPresidentialBunker(); err != nil {
> return "oops";
> }
> triggerDoomsdayDevice();
>
> If you don't assign the error, then the compiler could switch to standard
> exception semantics, e.g.:
>
> sealPresidentialBunker(); // <-- Since not assigning error, an exception
> would be thrown
> triggerDoomsdayDevice();
>
> This way you get both worlds.

Josh Holland

unread,
Sep 26, 2012, 4:02:36 AM9/26/12
to Nigel Tao, Ian Lance Taylor, golan...@googlegroups.com, Peter, knotw...@gmail.com, Patrick Mylund Nielsen

The problem I have with all of this syntax changing magic is that it makes it harder to see that the error actually is being handled. With the full "if err != nil { }" form, it is clear that the possibility of error is considered. However with the proposed "n, return = writer.Write(buf)" and $ styles, it's easy to miss the handling. A drastic change in control flow like returning should always stand out in its own statement.

Thanks,
Josh

--


Michael Jones

unread,
Sep 26, 2012, 4:30:04 AM9/26/12
to Josh Holland, Nigel Tao, Ian Lance Taylor, golan...@googlegroups.com, Peter, knotw...@gmail.com, Patrick Mylund Nielsen
Absolutely -- it needs to be clear. What we've been musing about is what it might achieve and how few "magic" things would be needed to do that. If a consensus built around it being an answer to a problem worth solving then indeed the serious design would need to be very clear to the coder, the debugger, and a stranger who looks at the code in 5 years.

Here is an example (just an example of the top of my head) how the example you cite could be clear as day:

root, handle(rangeError) := sqrt(-5.0)
x = (4+j)/(root + 1)
return x

handle {
case rangeError:
   :
    return error("complex root")
case overflow:
    :
}


this would add a new reserved word, let it appear as a "handle function call" with the rule that the call only happens when the assigned value is non-nil or non-xero. The call would be to the innermost handle switch. if you wanted the "call" could act as such a jump back top to the call site if the case does not return. Ot it could always return, or whatever. 

This may not be the best way to reduce the idea to practice, but it gives an example of ways to make the "I just might branch somewhere" logic explicit. No doubt sophisticated language designers could think of something much better. I just wanted to raise the idea that one nice feature of exceptions is the ability to disaggregate the call site and the error handling code should that be desired in a particular situation. One that I like would be handling the same problem with the same resolution in 20 places (something like "connection dropped" or "SIgnaling NaN" where that could serve a possibly large function with dozens of call sites. The existing ", ok" idiom would continue to work great in all the places where you wanted to handle the error there at the call site.

If the mechanism were general and policy free (nothing about errors, just good for handling them like defer and closing things) then you could also use it as an interesting implementation method for decision tables, complex branch structures of the kind in the Knuth paper I linked above, and other "non-local but logical" places where goto would otherwise be used.


--
 
 

Ethan Burns

unread,
Sep 26, 2012, 8:15:42 AM9/26/12
to golan...@googlegroups.com
This idea is interesting, but I it seems to be adding a rather large new concept to the language.  I wonder how this is better than Ian's original idea of assigning to 'return' coupled with defer (as pointed out by yiyus).  It seems like the return-based approach would be adding something simple and orthogonal (I cringe at this cliche now, but it is the case none-the-less).  In other words, you get the out-of-band error handling that you want by combining this hypothetical return-assignment approach  with something that already exists in the language, namely defer.  Another other benefit of the return-based approach is that, in many cases, the error is just being passed back up the call stack and more complex handling is not desired.  Finally, because defer works on any function call, it is possible that common error handling could be captured in a separate function that is re-used in many defer calls.


Best,
Ethan

Michael Jones

unread,
Sep 26, 2012, 9:34:09 AM9/26/12
to Ethan Burns, golan...@googlegroups.com
I agree. I like that specific feature too. Just illustrating realms of solutions for people with early questions about specifics. To me it seems that the most interesting questions now are, 

Q1: When and why would you want to separate the the code making the call from the code handling exceptional situations? This feels good to me for some cases, as when 20 call sites want to handle the same error, or when the code is very complex and I would be concerned that robust error checking in situ would obscure it. I don't know if others even feel the need in their type of programming.

Q2:  When and why would you want to have many instances of the minimal ",ok", "ok != nil", "return error to caller" in your code. If this is a sufficiently high frequency case, then maybe it is worth facilitating with some error-handling-and-sending-up-the-call-chain version of a function call or result assignment. (For example, instead of "go func" you could have "try func" with the return the last arg if not nil logic.)

From answers to these and related questions will flow knowledge of the best path...

Scott Pakin

unread,
Sep 26, 2012, 3:33:28 PM9/26/12
to golan...@googlegroups.com
Okay, here's my riff on this theme: What if Go were to interpret &f = x, where f is a function and x is an arbitrary value, as f(x)?  What does that have to do with exception handling?  Well, we can use a func(error)—or in some cases a func(bool)—to handle exceptional conditions:

myFile, &log.Fatal := os.Open("happy.txt")
data := make([]byte, 100)
count, &log.Fatal := myFile.Read(data)

Advantages: Exception handling is explicit.  Different calls within the same function can use either the same or different handlers.  Handler has the option of continuing the control flow or panicking to introduce non-local control flow.  Approach is not limited to just exceptions or just functions returning an error as the exceptional value.

What do you think?

— Scott

Rémy Oudompheng

unread,
Sep 26, 2012, 3:39:22 PM9/26/12
to Scott Pakin, golan...@googlegroups.com
It is already possible. See template.Must for example.

Rémy.

John Asmuth

unread,
Sep 26, 2012, 4:30:15 PM9/26/12
to golan...@googlegroups.com, Scott Pakin
Only possible if you write the function for the specific parameters expected. This is much more general, if a bit wonky.

I really don't think the slight inconvenience here merits a change to the language.

Kevin Gillette

unread,
Sep 26, 2012, 5:14:41 PM9/26/12
to golan...@googlegroups.com, Scott Pakin
The template.Must technique is limited since you have to make a specialized function to handle each set returned types. If the community were to rally around template.Must style handling, with a defer-recover to turn panics back into regular errors, then it'd be beneficial to have a "magic" builtin that takes any types on input, with the requirement that the last is a type assignable to the builtin error interface, and then panics if err != nil, or otherwise returns all but the error. For example:

func f() (err error) {
  defer func() { err = recover() }()
  // ...
  line, isPrefix := errchk(bufioReader.ReadLine())
  // ...
}

However, I rather dislike the idea of making panic an endorsed error management mechanism.

As long as Ian is talking about changing the nature of labels, a thought I had the other day, is along the same lines as errcheck, but instead takes a label as the first parameter, but returns all the arguments, including the error value:

func f(filename string) error {
  line, isPrefix, err := errgoto(handle1, bufioReader.ReadLine())
  info, err := errgoto(handle1, os.Stat(filename))
  errgoto(handle2, sealBunker())
handle1:
  return err
handle2:
  panic(err)
}

the problems here, of course, are:

1) the parser would have to be able to treat identifiers in function params as a label (without allowing an expression), which would require the grammar to be modified.

2) the call mechanism would need to be given an exception for this builtin, allowing all arguments _after_ the first to fit the existing f(g()) special case.

3) it would be more trouble than it's worth since you'd have to either declare most of your variables before any errgoto uses (same rules as goto -- can't skip over declarations), or you'd have to be excessive use of anonymous blocks, or declaration hoisting would have to be added to the language.

Suffice it to say, it's an idea, but I don't much like that either. I'm pretty happy with doing if/else chains anyway -- the ability to do assignments in the pertinent control structures makes this pleasant enough.

I think Ian's idea is 'neat' from a technical perspective, but is perhaps swaying a bit towards the dark side (since control flow would be magic -- it's a bit like "come from").

Dan Kortschak

unread,
Sep 26, 2012, 5:30:49 PM9/26/12
to Kevin Gillette, golan...@googlegroups.com, Scott Pakin
I'm pretty sure this has been suggested in the past.

Ben J

unread,
Sep 26, 2012, 12:18:09 PM9/26/12
to golang-nuts
Do we really want people to adopt Go who are so against a fundamental
part of the language? I think Go is popular enough now where the Go
community shouldn't have to convince people to try it.

It's great if you think Python|Ruby|C++|etc is better than Go. Write
your code in your preferred language, solve real world problems, and
be happy. Think of all the time we're all wasting reading and
replying to this thread rather than improving software.



On Sep 24, 6:52 pm, Patrick Mylund Nielsen <patr...@patrickmylund.com>
wrote:
> What DisposaBoy was pointing out is that your original post basically read,
> "Your error handling sucks! Some other guys said that your error handling
> sucks. Why does it suck? Too bad, now I won't use your language", and it
> was obvious that you haven't actually used the language yourself. You need
> to use the language, or at least study (more) code written in it, before
> you adopt and parrot somebody else's opinion, especially if you're going to
> post such a condescending/derisive message to that language's mailing list.
>
> Of course, that doesn't just apply to programming languages. Many
> programmers use NoSQL databases to be able to make "web scale"
> applications, and not RDBMS, even though they will likely be tens or
> hundreds of times as productive using something relational, and won't
> actually have the problems that Facebook has for messaging (they still use
> MySQL for everything else)--and one of the major reasons they're using
> these solutions is that Hacker News and reddit.com/r/programming are filled
> with threads that worship the latest new thing and dismisses RDBMSs as "old
> and bad" (when in reality they're some of the most mature pieces of
> software that exist.) Now that Google has unveiled Spanner, maybe all the
> programmers who made MongoDB applications will rave about ACID,
> transactional consistency and the ease-of-use of query languages... :) (It
> already exists I guess: "NewSQL".)
>
> My/our point is: Don't dismiss something because someone got to #1 on
> Hacker News criticizing it. In a lot of cases, they don't really know what
> they're talking about, so adopting their (misinformed) opinion is doing
> yourself a disfavor. NoSQL, or exceptions, may be right for you, but that
> may be the case far less often than you'd think if you ingest Hacker News
> articles uncritically. Try it, then make up your own mind.
>
>
>
>
>
>
>
> On Mon, Sep 24, 2012 at 6:35 PM, <knotwel...@gmail.com> wrote:
> > @DisposaBoy I do have my opinions, I just pointed to a blog that summed
> > it up quite nicely. If you tell me to jump of a bridge, I will probably
> > push you off instead. You are the one spamming the list with your reply
> > devoid of content.  As you can see, there has been quite some interest in
> > my sololoquy.
>
> > On Monday, September 24, 2012 2:47:22 PM UTC-5, DisposaBoy wrote:
>
> >> On Monday, September 24, 2012 4:55:57 PM UTC+1, (unknown) wrote:
>
> >>> Its a shame that such a fantastic language is missing a better way to
> >>> deal with errors.
> >>> Exceptions might not be perfect, but are damn better than checking each
> >>> and every function call.
>
> >>> Or am I missing something?
>
> >>> I just read a pair of posts that expresses these ideas much better than
> >>> what I could here.
>
> >>>http://uberpython.wordpress.**com/2012/09/23/why-im-not-**
> >>> leaving-python-for-go/<http://uberpython.wordpress.com/2012/09/23/why-im-not-leaving-python-...>
>
> >>>http://www.yosefk.com/blog/**error-codes-vs-exceptions-**
> >>> critical-code-vs-typical-code.**html<http://www.yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs...>
>
> >>> As one of the comments I read said: 99% of the time I need to code the
> >>> happy path and if something breaks in the middle the error handling is
> >>> exactly the same: log the error, close resources, send the caller an error
> >>> code or message, end of the story.  I don't want to check every freaking
> >>> single function invocation for errors.
> >>> Its a shame, I really wanted to use go.
>
> >> Form what you've said, it doesn't appear that you are able to form your
> >> own opinions. What happens if I tell you that it's a good idea to go
> >> jumping off bridges? ... In any case, please don't spam the list
>
> >  --

Patrick Mylund Nielsen

unread,
Sep 27, 2012, 12:41:11 AM9/27/12
to knotw...@gmail.com, golan...@googlegroups.com
This is a silly argument, IMO. Just check the error values. If you are actively ignoring them you are doing the equivalent of try: foo; except: pass.

On Wed, Sep 26, 2012 at 11:33 PM, <knotw...@gmail.com> wrote:

Ok, here is a dumbded down example of what I mean:

package main

import (
"bufio"
"os"
)

func main() {
file, _ := os.OpenFile("/nowhere/", os.O_WRONLY|os.O_CREATE, 0666)
writer := bufio.NewWriter(file);
writer.WriteString("foobar\n")
}

Run this, and what will you get? Nothing. No error, no stacktrace ... absolutely nothing. Nada.

I know that programers should check the error codes and should be super smart, and should have tests for their code, and should not have deadlines, and should be handsome ... but in reality, well you have been there.
This applies to any error handling mechanism error codes, exceptions or you name it... as someone mentioned Go (or any language) will not do the error checking, the programmer will.
So when the programmer, god forbid, fails to do his job I would rather have a180 line stacktrace pinpointing me where the stupid programmer messed up.


On Monday, September 24, 2012 10:55:57 AM UTC-5, (unknown) wrote:

Its a shame that such a fantastic language is missing a better way to deal with errors. 
Exceptions might not be perfect, but are damn better than checking each and every function call.

Or am I missing something?

I just read a pair of posts that expresses these ideas much better than what I could here.


As one of the comments I read said: 99% of the time I need to code the happy path and if something breaks in the middle the error handling is exactly the same: log the error, close resources, send the caller an error code or message, end of the story.  I don't want to check every freaking single function invocation for errors.
Its a shame, I really wanted to use go.

--
 
 

Dave Cheney

unread,
Sep 27, 2012, 1:08:24 AM9/27/12
to knotw...@gmail.com, golan...@googlegroups.com
With respect, your translation is incorrect, If you were to ignore the
error in Java, as you had in Go you would have arrived at

public class Foo {
public static void main(String[] args) {
try {
File file = new File("/nowhere/");
OutputStreamWriter writer = new OutputStreamWriter(new
FileOutputStream(file));
writer.write("foobar\n");
} catch (Exception e) { // ignored }
}
}

Dan Kortschak

unread,
Sep 27, 2012, 1:15:07 AM9/27/12
to knotw...@gmail.com, golan...@googlegroups.com
Similarly, I have found that people who drive with their eyes closed
tend to have car accidents.

If you actively ignore the error return as you have, yes, you will have
problems. Now if you were talking about single return functions that
return errors and can be ignored without an explicit discard, there
might be a little more validity to your point.

Jesse McNelis

unread,
Sep 27, 2012, 1:48:21 AM9/27/12
to knotw...@gmail.com, golan...@googlegroups.com
On Thu, Sep 27, 2012 at 3:04 PM, <knotw...@gmail.com> wrote:
> public class Foo {
> public static void main(String[] args) throws Exception {
> File file = new File("/nowhere/");
> OutputStreamWriter writer = new OutputStreamWriter(new
> FileOutputStream(file));
> writer.write("foobar\n");
> }
> }

You couldn't argue that the Go code you posted was correct because
it's obviously not.
But it's often argued that this Java code is, because some other code
will do the error handling or the user will get a completely useless
stack trace (and thus the error is 'handled')
So developers write large amounts of code without any error handling
and nobody ever actually handles the errors.
Eventually the errors bubble up to the top of the stack where there is
no longer any context to do error handling and the best you can do is
log them and restart.

Because throwing errors from your APIs becomes such a low code
overhead (if you don't do any handling) more and more APIs start
throwing errors as they don't feel a need to minimise this because
people not handling errors don't feel the pain which makes it much
more of a pain for those writing good code.

Look at Java/Python/Ruby APIs they all throw exceptions for silly
reasons and most code doesn't bother handling any of them. Trying to
write correct python code that actually handles errors is largely an
impossibility in any code base of reasonable scale.

Go makes the error checking a little more error prone in an attempt at
making errors more visible to encourage programmers to actually
properly handle and think about them.

--
=====================
http://jessta.id.au

Nigel Tao

unread,
Sep 27, 2012, 2:09:59 AM9/27/12
to Jesse McNelis, knotw...@gmail.com, golan...@googlegroups.com
On 27 September 2012 15:48, Jesse McNelis <jes...@jessta.id.au> wrote:
> Trying to
> write correct python code that actually handles errors is largely an
> impossibility in any code base of reasonable scale.

I came across http://www.python.org/dev/peps/pep-0380/ the other day.
I am not a fluent Python programmer, so this may be unfair, but I find
the handles-exceptions-correctly code that follows "The statement
RESULT = yield from EXPR is semantically equivalent to" to be very
difficult to understand.

Kevin Gillette

unread,
Sep 27, 2012, 3:11:45 AM9/27/12
to golan...@googlegroups.com, benjamin...@gmail.com
On Wednesday, September 26, 2012 10:18:09 AM UTC-6, Ben J wrote:
Do we really want people to adopt Go who are so against a fundamental 
part of the language?  I think Go is popular enough now where the Go 
community shouldn't have to convince people to try it. 

It's great if you think Python|Ruby|C++|etc is better than Go.  Write 
your code in your preferred language, solve real world problems, and 
be happy.  Think of all the time we're all wasting reading and 
replying to this thread rather than improving software.

I agree with this sentiment entirely, though I'll add that I believe Go is popular because it didn't sacrifice its integrity in the name of popularity.

Larry Clapp

unread,
Sep 27, 2012, 6:27:11 AM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com
I remain unconvinced.  You might as well say

-- perl --
open( OUT, ">/nowhere/" );
print OUT "foobar\n";
-- /perl --

It's just as stupid and just as wrong.

And I find your later Java code equally unconvincing.  I find it pretty crazy that "file not found" throws an exception.  I'm sure this argument has been made thousands of times, but that just doesn't seem like something very exceptional to me.  I also agree with Dave Cheney that your Java translation is inaccurate.  From that point of view, Go allows you to ignore the error much less verbosely!

I guess, bottom line, Go gives you a little more rope than Java does.  It's like C or Perl in that particular sense.  If you want to write Go, I think you have two choices: you can establish better habits, or you can write a library that panics in all the places you consider appropriate.  (But, ew.)

I won't tell you that if you write more Go you'll learn to love it, or even like it.  (You might, but I won't say you will.)  But I do think that if you like the rest of the language, like the goroutines and channels, then have at it, and grin and bear it on this particular issue.  Frankly, I bet if you think about it, you'll find some things that Java sucks at that Go excels at.

-- Larry

Raph

unread,
Sep 27, 2012, 6:35:08 AM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com
+1

Dumitru Ungureanu

unread,
Sep 27, 2012, 8:53:37 AM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com
package main

import (
    "os"
)
func main() {
    file := "/nowhere/"
    text := "Prone to error"
    print(writeToFile(file, text), "\n")

    file = "here.txt"
    text = "This might just work"
    print(writeToFile(file, text), "\n")
}
// writeToFile takes two string arguments 
// a file name and a string to write to that file
// and returns an error string for the write operation
func writeToFile(f, s string) (expl string) {
    var e int
    if file, err := os.OpenFile(f, os.O_RDWR|os.O_CREATE, 0666); err == nil {
        if _, err := file.WriteString(s); err == nil {
            e = 0
        } else {
            e = 1
        }
    } else {
        e = 99
    }

    return explainError(e) + f
}
// explainError takes the file name and the error index
// and returns an explicit error text
func explainError(e int) (s string) {
    switch e {
    case 0:
        s = "Successful write to file: "
    case 1:
        s = "There was an error writing to file: "
    case 99:
        s = "You got the file name (and/or its path) wrong: "
    }

    return s

Steven Rice

unread,
Sep 27, 2012, 9:20:51 AM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com
So you want exceptions to arise? It sounds like you want to work with bad programmers. The only reasons exceptions exist is to force someone to handle an error, if you really need an exception to remind you to think about what can go wrong in your code, to remind you to check and sanitize your input, to remind you to program, then you are not a very good programmer. Don't work with APIs that ignore errors, don't write APIs that ignore errors. If you do that then you'll never have to worry about them. If you work in a team of potentially bad programmers, here's an idea: write each others test cases as well as your own. Think of input that they may not expect (like your non existent file name) and see if it passes. 

Harley Laue

unread,
Sep 27, 2012, 12:43:34 PM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com
In addition to the "letting someone else deal with it" mentality of
exceptions, it's also done at runtime. So poorly tested code and code
paths that aren't taken frequently are more likely to crash your
program. Whereas the provided example, the programmer actively and
knowingly ignored the error. So this is a particularly bad example
(and as other have pointed out, it's actually less verbose to ignore
the error in Go than it is in exception based languages :P)

I think I'm done watching this thread. There's nothing anyone can say
to show the knotwelkum that he is misguided at best (or IMO wrong) in
his opinions of how errors should be handled (in his case, not
handling them until it blows up.) With everything that's already been
said, I think he must be content writing buggy/untested code. I guess
that's just his prerogative.
> --
>
>

David Leimbach

unread,
Sep 27, 2012, 4:52:05 PM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com

<cutting a lot, sorry.  Trying to get to the meat of your point, I think>

So when the programmer, god forbid, fails to do his job I would rather have a180 line stacktrace pinpointing me where the stupid programmer messed up.



If Go provided stack traces for errors that were != nil, and not captured in a variable would you think Go's error handling was better?  

My thinking is something like

x, _ := f();

is an explicit ignoring of the error from f(), and that if an error occurs, nothing new should happen.

However for calls like

fmt.Printf("blah")

This is not explicitly ignoring the error, and one could say the lazy programmer should be told about such a failure.  If you really don't care you must write

_,_ = fmt.Printf("blah")

or 

numBytes, _ := fmt.Printf("blah")

instead.  

This is a lot better than having exceptions creep up the call stack to be ultimately squelched by a

catch (Exception e) {}

The error type is literally part of the language so I suspect someone could one day do something about this, if it made sense to do so.

It could be pretty ugly to implement, but I've never tried to do such a thing, so perhaps not?

I still feel very strongly that errors should not propagate up the stack unless explicitly wired to do so via a chain of error returns, because implicit behaviors are dangerous in general and have been a source of bugs in languages like C++ for years (like 'explicit' keywords for single argument constructors).  

Being explicit really helps with readability and maintenance of code bases.  Writing the code is only part of the story of a software life cycle.


Patrick Mylund Nielsen

unread,
Sep 27, 2012, 5:21:45 PM9/27/12
to knotw...@gmail.com, golan...@googlegroups.com
> but the bad programmer will still just do _,_ := x() just to get past it.

FTFY

In languages with exceptions, ignoring errors is implicit and excusable. In Go, it is explicit and inexcusable. That leads to better code on average. Only code written by bad programmers will be riddled with "foo, _ := somethingThatMightFail()".

On Thu, Sep 27, 2012 at 4:04 PM, <knotw...@gmail.com> wrote:

Not really. The problem with your "suggestion" is that it would be caught at compile time (which is good) but the lazy programmer will still just do _,_ := x() just to get past it.
The real problem is at runtime, where you would be completely lost as to where the problem is.
Of course the same goes for exceptions.  The lazy programmer could simply catch and ignore the exception...(that is also why I favor unchecked exceptions... but that is another matter).

Thanks to all for your answers.

--
 
 

Kevin Gillette

unread,
Sep 27, 2012, 5:33:51 PM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com
I very often see, `_, err := something()`, but I've yet to see an experienced go programmer do `x, _ := something()`. What that tells me is the error is the last thing that a normal go programmer will ignore.

andrey mirtchovski

unread,
Sep 27, 2012, 5:36:48 PM9/27/12
to Kevin Gillette, golan...@googlegroups.com, knotw...@gmail.com
> the error is the last thing that a normal go programmer will ignore.

but go-nuts threads about Go Errors are the first things normal go
programmers will ignore ;)

David Leimbach

unread,
Sep 27, 2012, 7:21:03 PM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com


On Thursday, September 27, 2012 2:04:02 PM UTC-7, (unknown) wrote:

Not really. The problem with your "suggestion" is that it would be caught at compile time (which is good) but the lazy programmer will still just do _,_ := x() just to get past it.

Lazy programmers are ok.  It's the crappy ones you can't do anything about.

Also I was not suggesting something that would get caught at compile time.  Please re-read my post.  My point was that since errors are a built-in type in the Go language, the compiler can leave behind code to emit a stack trace like thing when something "non-nil" happens where an otherwise not-explicitly ignored error would go.  I'll admit this seems pretty heavy handed, and possibly is quite stupid to do, but it might address some people's criticisms and might be worth a real discussion.

That would make it so that the programmer who's ignoring errors on purpose could write something really explicit like "_,_ = blah()" to say "I really don't care about this error".  But folks who write just "blah()", will get a stack trace if something occurs, because they didn't explicitly ask for the error to be ignored.

I've seen no examples of languages that address the "bad programmer problem".  What I think can be done is make it very explicit in code where people are doing "bad things".

I don't think we can stop people from doing bad things in a language.  Even Haskell has unsafePerformIO, which can turn something like ``myprint "hello" '' into something that means "fire all the missles!" 

 
The real problem is at runtime, where you would be completely lost as to where the problem is.
Of course the same goes for exceptions.  The lazy programmer could simply catch and ignore the exception...(that is also why I favor unchecked exceptions... but that is another matter).

You can easily catch and ignore unchecked exceptions.  

In C++ it's as simple as 

catch(...) {}

In Java you can catch Throwable, which can even catch OutOfMemoryError.  

Thanks to all for your answers.

On Thursday, September 27, 2012 3:52:05 PM UTC-5, David Leimbach wrote:

David Leimbach

unread,
Sep 27, 2012, 7:28:52 PM9/27/12
to golan...@googlegroups.com, knotw...@gmail.com


On Thursday, September 27, 2012 2:33:51 PM UTC-7, Kevin Gillette wrote:
I very often see, `_, err := something()`, but I've yet to see an experienced go programmer do `x, _ := something()`. What that tells me is the error is the last thing that a normal go programmer will ignore.

So maybe I was on to something with my proposal?   (Or perhaps just "on something")

_,_ = something()

in the case where you're really sure you want to explicitly ignore the error.  This is really uncommon, and should stick out like a sore thumb.

_,err := something()

when you really want to only handle the error.  this seems idiomatic to go.

and get a stack trace from the run time for ignoring the error when you do

something()

without ever even capturing the possibility of an error happening, but only when the error really happens!   People would choose this approach when they're doing something innocuous which may usually never fail, but when it does you just expect things to crash anyway.  

Dave Cheney

unread,
Sep 27, 2012, 7:53:38 PM9/27/12
to David Leimbach, golan...@googlegroups.com, knotw...@gmail.com
> and get a stack trace from the run time for ignoring the error when you do
>
> something()
>
> without ever even capturing the possibility of an error happening, but only
> when the error really happens! People would choose this approach when
> they're doing something innocuous which may usually never fail, but when it
> does you just expect things to crash anyway.

So, to clarify, your proposal is

fmt.Println("Hello world")

should panic if any return value of type error from this function, is
not assigned to a variable (or the _ variable), and that value would
be non nil ?

Cheers

Dave

Michael Jones

unread,
Sep 27, 2012, 7:58:47 PM9/27/12
to David Leimbach, golan...@googlegroups.com, knotw...@gmail.com
Interesting! Some points to consider:

+ Ignoring function return values, or one or more of the final ones, is a capability of the language.

+ Some functions use a return value, often the final one, to signal an error.

+ Some call sites of functions that return a final error argument ignore it. 

There are varying opinions on how best to deal with error returns (always check, never check, sometimes check and hope for the best, etc.) and also on what should happen when a returned error is ignored. What does not seem to be mentioned is that the *language* does not know about errors. There is a package "errors" and the standard library uses it, so you could say that there is a convention about error handling, but I don't think we can say that the compiler is aware of anything special. (Am I wrong?)

Given this state of affairs, I'm not sure what magic enforcement a compiler can do for unexamined final return values that happen to have special meaning to a package.

Of course, there is still the option of making an error something that the language understands and thus can enforce in various ways.

--
 
 

Ian Lance Taylor

unread,
Sep 27, 2012, 8:34:20 PM9/27/12
to Michael Jones, David Leimbach, golan...@googlegroups.com, knotw...@gmail.com
On Thu, Sep 27, 2012 at 4:58 PM, Michael Jones <m...@google.com> wrote:
>
> There are varying opinions on how best to deal with error returns (always
> check, never check, sometimes check and hope for the best, etc.) and also on
> what should happen when a returned error is ignored. What does not seem to
> be mentioned is that the *language* does not know about errors. There is a
> package "errors" and the standard library uses it, so you could say that
> there is a convention about error handling, but I don't think we can say
> that the compiler is aware of anything special. (Am I wrong?)

The name "error" is a predeclared identifier in the language, like
"int" and so on. So while the language doesn't currently give that
type any special semantics, and I'm not at all sure that it should, it
is at least within the realm of possibility.

Ian

Michael Jones

unread,
Sep 27, 2012, 8:52:07 PM9/27/12
to Ian Lance Taylor, David Leimbach, golan...@googlegroups.com, knotw...@gmail.com
...which leaves open a long list of options, like:

func (name *type) example(arg int) (int, float64, error) { }

and

a, b := example(1)

where the compiler knows that there is an error returned and that it has special powers, as in the above where the implication could be there is an unchecked error here, so I will:

1. refuse to compile

2. print a stack trace when error is non-nill. ;-)

3. only compile if the function making the call ALSO has an error return and when error comes back non-nill, automatically return from the function and pass that error as the function's error value. (implicit assignment of invisible return value and invisible "if not ok return error") in such cases. Rob might puke all over this, but it is one of the possibles. Think of this as a soft exception. It only means that errors are always unpacked from the return and examined, making ",ok" universal even when uncoded by the developer.

4. similar to #3 but instead of returning, look for an error switch in scope and use that if it exists.

:
many others ideas, no doubt

David Leimbach

unread,
Sep 27, 2012, 8:55:12 PM9/27/12
to golan...@googlegroups.com
Yeah. Errors are special in the language to a degree and I don't know that I'm advocating any changes yet; simply sugesting that one can potentially provide different default behavior for error since it is already special.

Also I'm saying that behavior can be explicitly overridden in a way that you could read and identify fairly quickly reusing the token that currently means "ignore" for that purpose.

It almost feels consistent enough to be reasonable. I question the overall value of it though.

I wonder how it would impact the existing corpus of go 1.0+ code.

David Leimbach

unread,
Sep 27, 2012, 8:55:45 PM9/27/12
to golan...@googlegroups.com

si guy

unread,
Sep 27, 2012, 10:48:12 PM9/27/12
to golan...@googlegroups.com
Are you suggesting a function definition flag that says "mr. Compiler, please error if my return values are ignored."?
Something like if func is capitalized?

Kosztka Imre Dávid

unread,
Sep 28, 2012, 12:55:41 AM9/28/12
to si guy, golan...@googlegroups.com
Let's start writing functions where the error is the first return
value. If someone wants to use it's return value s/he has to ignore it
or deal with it. If the programmer doesn't want to use the return
value we are still in trouble.

2012/9/28 si guy <sjw...@gmail.com>:
> Are you suggesting a function definition flag that says "mr. Compiler, please error if my return values are ignored."?
> Something like if func is capitalized?
>
> --
>
>



--
Name : Kosztka Imre Dávid
E-mail: kosz...@gmail.com
Phone number: +36309213462
Mailing address: H-3700, Hungary Kazincbarcika Szeder utca 2.

Larry Clapp

unread,
Sep 28, 2012, 8:35:59 AM9/28/12
to golan...@googlegroups.com, Ian Lance Taylor, David Leimbach, knotw...@gmail.com
On Thursday, September 27, 2012 8:52:54 PM UTC-4, Michael Jones wrote:
...which leaves open a long list of options, like:

func (name *type) example(arg int) (int, float64, error) { }

and

a, b := example(1)

where the compiler knows that there is an error returned and that it has special powers, as in the above where the implication could be there is an unchecked error here, so I will:

1. refuse to compile

2. print a stack trace when error is non-nill. ;-)

3. only compile if the function making the call ALSO has an error return and when error comes back non-nill, automatically return from the function and pass that error as the function's error value. (implicit assignment of invisible return value and invisible "if not ok return error") in such cases. Rob might puke all over this, but it is one of the possibles. Think of this as a soft exception. It only means that errors are always unpacked from the return and examined, making ",ok" universal even when uncoded by the developer.

I think I would puke all over it too, just by the way.  :)

Let's not forget that "error" is just an interface: a type that happens to implement a method "Error() string".  I'm pretty sure I wouldn't want to give defining such a function such magical powers.  (This applies to the whole discussion, of course, not just this particular proposal/observation.)

-- L

Dumitru Ungureanu

unread,
Sep 28, 2012, 8:39:11 AM9/28/12
to golan...@googlegroups.com, knotw...@gmail.com
This won't return any errors, but it doesn't mean all went according to the programmer's plan:

strings.Replace("Hello World", "l", "z", 20)


"Run this, and what will you get? Nothing. No error, no stacktrace ... absolutely nothing. Nada."

This means that I can safely conclude now that Go Error Handling Sucks ?

:)


On Thursday, September 27, 2012 7:33:52 AM UTC+3, (unknown) wrote:

Ok, here is a dumbded down example of what I mean:

package main

import (
"bufio"
"os"
)

func main() {
file, _ := os.OpenFile("/nowhere/", os.O_WRONLY|os.O_CREATE, 0666)
writer := bufio.NewWriter(file);
writer.WriteString("foobar\n")
}

Run this, and what will you get? Nothing. No error, no stacktrace ... absolutely nothing. Nada.

I know that programers should check the error codes and should be super smart, and should have tests for their code, and should not have deadlines, and should be handsome ... but in reality, well you have been there.
This applies to any error handling mechanism error codes, exceptions or you name it... as someone mentioned Go (or any language) will not do the error checking, the programmer will.
So when the programmer, god forbid, fails to do his job I would rather have a180 line stacktrace pinpointing me where the stupid programmer messed up.


Larry Clapp

unread,
Sep 28, 2012, 8:41:15 AM9/28/12
to golan...@googlegroups.com, si guy
The position of the error doesn't matter.  This gives a compiler error:

n := fmt.Println("Hello, playground")

prog.go:7: multiple-value fmt.Println() in single-value context


If you accept any return values at all, you have to accept or ignore them all.

-- L

Dumitru Ungureanu

unread,
Sep 28, 2012, 8:45:17 AM9/28/12
to golan...@googlegroups.com, knotw...@gmail.com
No.

It would mean that I have to get better at Go programming! ;)

strings.Replace("Hello World", "l", "z", strings.Count("Hello World", "l"))

David Leimbach

unread,
Sep 28, 2012, 11:12:45 AM9/28/12
to golan...@googlegroups.com


On Thursday, September 27, 2012 7:48:12 PM UTC-7, si guy wrote:
Are you suggesting a function definition flag that says "mr. Compiler, please error if my return values are ignored."?
Something like if func is capitalized?
 
No I'm not asking for the compiler to reject the code, but to provide different behavior.

I'm proposing that the compiler could generate code that when met with the following source:

fmt.Printf("blah")

the compiler could note that you did nothing with the error that's returned from that function, and rewrite it to behave as if you'd written something like this:

_, ___error = fmt.Printf("blah")
if ___error != nil {
    panic(___error)
}

This adds the behavior that uncaptured errors are converted to a panic at runtime if and only if the error occurs (is not nil)

If the compiler saw you ignoring the error and the return value explicitly it does nothing special.
For example:

_,_ = fmt.Printf("blah")

means exactly that.  "I don't care about errors, and I explicitly told you I do not".

This seems roughly equivalent to catch(Exception) {} (java) or catch(...) {} (c++).  This gives the programmer the flexibility to do "bad stuff", which should be allowed, but not be the default.

So no, I don't want the compiler to error and reject the code, I want the compiler to generate code to do something other than ignore the error you implicitly ignored by not doing anything about it.

The whole point in saying this might be worth while is that at least some folks seem to think uncaught exceptions in general are superior to the silently ignored errors which cause no side effects in the execution of the code.  I think they might have a point to make but are saying it in horribly unfriendly ways like "your error handling sucks".

My thoughts are it's almost exactly what they're asking for with exceptions anyway, but for this one behavior of implicitly ignored errors having no effect.  I believe ignoring errors is generally really bad Go code, and makes programs more difficult to debug.  This might be a way to say "ok be lazy if you wish, but we're going to spank you for it"

I also think it might be the sort of thing one could opt into (or out of) with a compiler flag, and not have it be default behavior because I see no reason why this absolutely must be done in a uniform way across modules.

Note I'm just throwing this out there as something that could potentially be experimented with as a compromise, but it might be that this compromise isn't a good idea to begin with and we tell people to "shut up and code Go the right way".

I'm not particularly attached to the idea, but I do think it might be worth exploring at least as a concept.  Feel free to tell me I'm being dense and that things are fine as is, but I've often thought that perhaps Go can be a little verbose if my default behavior is to crash on error anyway.

Dave

David Leimbach

unread,
Sep 28, 2012, 11:16:17 AM9/28/12
to golan...@googlegroups.com, knotw...@gmail.com


On Friday, September 28, 2012 5:39:11 AM UTC-7, Dumitru Ungureanu wrote:
This won't return any errors, but it doesn't mean all went according to the programmer's plan:

strings.Replace("Hello World", "l", "z", 20)

"Run this, and what will you get? Nothing. No error, no stacktrace ... absolutely nothing. Nada."

This means that I can safely conclude now that Go Error Handling Sucks ?

:)

It means the author of that function decided not to report errors when things didn't go well.  (perhaps because there's no way to know if things went "well-enough" for the caller anyway)

You can implement that kind of behavior in any language :-)

Dumitru Ungureanu

unread,
Sep 28, 2012, 11:45:22 AM9/28/12
to golan...@googlegroups.com, knotw...@gmail.com
Just to be on the safe side, of being properly understood that is, I'll reiterate from my posts:


1. This means that I can safely conclude now that Go Error Handling Sucks ?

strings.Replace("Hello World", "l", "z", 20)

2. No. It would mean that I have to get better at Go programming! ;)

strings.Replace("Hello World", "l", "z", strings.Count("Hello World", "l"))


The fact that Go silently oversees 17 bad iterations for Replace is a plus for Go, while 20 is a minus for the programmer.

My point is that, in Go or in Java, a programmer may randomly opt for stuff, like settling for a plain 20. Or it may choose to handle it with calculations like strings.Count("Hello World", "l"). The tools are there.

Steve McCoy

unread,
Sep 28, 2012, 12:45:08 PM9/28/12
to golan...@googlegroups.com, knotw...@gmail.com
I know this isn't your point, but just in case you didn't know: You can give strings.Replace a negative count and it will replace as many times as possible.

Dumitru Ungureanu

unread,
Sep 28, 2012, 1:24:14 PM9/28/12
to golan...@googlegroups.com, knotw...@gmail.com
Which takes us to Java String replace Sucks:

String   replace (char oldChar, char newChar)
  Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar .
String   replaceAll ( String regex, String replacement)
  Replaces each substring of this string that matches the given regular expression with the given replacement.
String   replaceFirst ( String regex, String replacement)
  Replaces the first substring of this string that matches the given regular expression with the given replacement.

What? No overloading?


Meanwhile, in Go:

func Replace

  func Replace(s, old, new string, n int) string 

Replace returns a copy of the string s with the first n non-overlapping instances of old replaced by new. If n < 0, there is no limit on the number of replacements.

It can't get simpler or clearer than that.

chris dollin

unread,
Sep 28, 2012, 1:35:20 PM9/28/12
to Dumitru Ungureanu, golan...@googlegroups.com, knotw...@gmail.com
On 28 September 2012 18:24, Dumitru Ungureanu <itmi...@gmail.com> wrote:
Which takes us to Java String replace Sucks:

String   replace (char oldChar, char newChar)
  Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar .
String   replaceAll ( String regex, String replacement)
  Replaces each substring of this string that matches the given regular expression with the given replacement.
String   replaceFirst ( String regex, String replacement)
  Replaces the first substring of this string that matches the given regular expression with the given replacement.

What? No overloading?

Overloading doesn't help with replaceFirst vs replaceAll, since both methods
need a matching regex String and a replacement string.

[I agree that the whole String-as-String, String-as-regex, Pattern business is
 as messy as a vampire's breakfast.]

Meanwhile, in Go:

func Replace

  func Replace(s, old, new string, n int) string 

Replace returns a copy of the string s with the first n non-overlapping instances of old replaced by new. If n < 0, there is no limit on the number of replacements.

It can't get simpler or clearer than that.

You're not comparing like capabilities. strings.Replace doesn't
give you access to matching-with-regexps the way replaceFirst
and replaceAll do. Of /course/ it's documentation is shorter.

[Also, it has less legacy code to contend with. This To Shall Pass.]

Chris

--
Chris "allusive" Dollin

Dumitru Ungureanu

unread,
Sep 28, 2012, 1:42:35 PM9/28/12
to golan...@googlegroups.com, Dumitru Ungureanu, knotw...@gmail.com, ehog....@googlemail.com
It should, since overloading is also about the number of params, not only about their type.

And you're right comparing like capabilities ;) In Go, for regexp there's the http://golang.org/pkg/regexp/ package.

Kevin Gillette

unread,
Sep 28, 2012, 5:09:11 PM9/28/12
to golan...@googlegroups.com
I think that's the job for a tool like `go vet`, and even then, it should be configurable to allow user-definable whitelists and blacklists (black takes precedence) of functions/methods or packages which should or should not be considered problematic when errors are ignored (like whitelist fmt, but blacklist any of the fmt.Scan* functions, for example).

Putting it in the compiler would, imo, be bad because either, by popular demand, we'd need a gcc-style switch like -fno-ignored-errors, which would break the policy of compiler simplicity (convention over configuration), or alternatively, we'd have to amend all our code to say:

  _, _ = fmt.Println("I don't care if you don't see this")

and that's pretty terrible too

Dan Kortschak

unread,
Sep 28, 2012, 5:50:11 PM9/28/12
to Kevin Gillette, golan...@googlegroups.com
Or, if you really wanted this behaviour, it would not be too difficult to write a tool that processed a source file (comparing against black/white lists) and added that conditional and panic decoration.
--
 
 

gabriel...@hootsuite.com

unread,
Jun 10, 2017, 11:19:26 AM6/10/17
to golang-nuts, knotw...@gmail.com
Indeed, error handling sucks in Go, but it sucks in other languages too! 
I think it is more about standardizing error types across libraries than anything else... 

On Monday, September 24, 2012 at 11:04:55 AM UTC-7, Aram Hăvărneanu wrote:
     .-'\
   .-'  `/\
.-'      `/\
\         `/\
 \         `/\
  \    _-   `/\       _.--.
   \    _-   `/`-..--\     )
    \    _-   `,','  /    ,')
     `-_   -   ` -- ~   ,','
      `-              ,','
       \,--.    ____==-~
        \   \_-~\
         `_-~_.-'
          \-~

--
Aram Hăvărneanu

id: 7898659753248090
Reply all
Reply to author
Forward
0 new messages