Why I’m not leaving Python for Go

First of all, Go seems like a great language. It has an excellent tutorial which I joyfully went through and found:

  • Go is Fast.
  • Concurrent by design.
  • Typed (important for JIT and IDE’s) but not cumbersome and ugly like C or C++’s spirals.
  • Duck-type-esque interfaces.
  • The defer mechanism is really nifty.

But there’s one problem I can’t live with. Which is a shame as I was eager to make the leap of faith in the name of concurrency. That problem is errors are handled in return values. 70’s style.

Verbose and repetitive error handling

The designers of go consider this a virtue.

In Go, error handling is important. The language’s design and conventions encourage you to explicitly check for errors where they occur (as distinct from the convention in other languages of throwing exceptions and sometimes catching them). In some cases this makes Go code verbose, but fortunately there are some techniques you can use to minimize repetitive error handling.

This is one of the things I can’t stand in C. Every single line requires an if statement to prevent programs from doing crazy things. This is an official, canonical example from the aforementioned link with perhaps “minimal repetitive error handling”:

    if err := datastore.Get(c, key, record); err != nil {
        return &appError{err, "Record not found", 404}
    }
    if err := viewTemplate.Execute(w, record); err != nil {
        return &appError{err, "Can't display record", 500}
    }

The correct way to call a function in Go is to wrap it in an if statement. Even Println returns an error value that I’m sure most on the planet will never check. Which brings me to…

Errors passing silently – ticking time bombs to go

To quote Tim Peters:

Errors should never pass silently
Unless explicitly silenced

Go isn’t just stuck with verbose and repetitive error handling. It also makes it easy and tempting to ignore errors. In the following program we would trigger the doomsday device even if we failed protecting the presidential staff.

func main() {
    http.Get("http://www.nuke.gov/seal_presidential_bunker")
    http.Get("http://www.nuke.gov/trigger_doomsday_device")
}

What a shame. Oops.

In theory we could require the programmer never ignore returned errors. By static analysis or convention. In practice it’d be a pain worth enduring only in the most error critical programming tasks. Perhaps that’s Go’s purpose.

panic/recover

Panic and recover aren’t good enough as long as the standard library rarely uses them. Why is an array out of bounds any more cause for panic than a bad format string or a broken connection? Go wanted to avoid exceptions entirely but realizing they can’t – a few exceptions were tacked on here and there, leaving me confused as to which error happens when.

Perhaps another time

So I say this with much regret because Go has a lot of amazing ideas and features, but without modern error handling – I’m not going.

I’m still waiting for that open source, concurrent, bottom left language to come along. Any suggestions are more than welcome.

127 thoughts on “Why I’m not leaving Python for Go

  1. The single thing I hate most about Python programs (or Ruby programs) is the lack of error handling. On COUNTLESS occasions programs have blown up in front of me, and when they are written in Python (or Ruby), I most often just get an unhelpful stacktrace.

    I, too, consider it a virtue that Go takes error checking seriously. Whenever I write code, I’d do it that way anyways.

    • IMHO The Python tracebacks (i dont know about Ruby ones) are quite verbose and explicits. Also extensive error handling is available to the programmer, only if he decides to use it seriously which is rarely the case i admit 🙂

    • As a fairly new starter to Python, I have to say that the error handling in it is pretty obvious most of the time. Makes things easy to deal with.

      Go was my target for a 2nd language to learn, and I’m still looking forward to it because this one issue that someone has about error handling is nothing to be concerned about. It’s just a case of accepting change and getting use to i.

      • The writer is correct in saying returning error codes is 70s error handling. All they tell you is “something went wrong”. Python’s exception handling is considerably more verbose and by declaring your own exception classes you can effectively monitor, handle and debug code often by simply looking at the class of exception raised.

        Change that move your forward is good. Changes that moves you backward is not so good. This isn’t a two steps forward one step back, error code returns are many many steps back as far as exception handling goes.

    • Python’s stack traces, combined with the error message text, typically contain exactly enough information to tell you what went wrong and exactly where the error occurred. Of course, you have to actually read the stack trace to get anything useful out of it.

      • Exactly. Error returns contain a single integer. I’ve got this Error 302 here. What should we do? Whereas an Python traceback has the entire context of the failed operation, containing, hopefully enough context for the developer to fix the problem. Go’s design expects authors to construct, in 10,000 locations throughout their code, a manual traceback of what went wrong. What a failure by the language designers, and all because of their 70s era Fear of Exceptions.

        W

    • I hear you. Maybe I have a skewed sample but it seems like Python dev prefer to dump a stack trace on on you instead of writing actual error messages.

      I think I prefer Go’s stronger emphasis on actually handling errors and writing something useful to the user. Not everybody is a python developer and can parse python stack back traces.

    • The problem you describe is mostly due to Python’s of lack of compile-time checking (usually related to no static type checking). There is a bug in the code, and you don’t find out until you run it.

      The good thing about Python is bugs related to failing to explicitly handle an error IMMEDIATELY kills the program and gives a traceback pointing at exactly where things went wrong. In Go, a bug related to failing to explicitly check for an error will allow the error to propagate through the program until something really blows up, sometimes long after and far away from where the error really happened, making it very hard to find the real cause.

      Note that Python requires you to explicitly ignore an error, Go requires you to explicitly check for an error. So lazy coding mistakes in Python results in errors being raised, but lazy coding mistakes in Go results in errors being ignored.

      Go doesn’t “take error checking seriously”, it requires and encourages programmers to “take error checking seriously”, because it’s not going to do it for you.

  2. Exceptions are not a sane error handling strategy; this is. Exceptions may seem fine under a traditional “OS threads” concurrency model. Once you move into asynchronous execution territory, exceptions are absolutely terrible to deal with. I must ask, have you ever written truly asynchronous code? I’m speaking from a .NET developer’s perspective, primarily focused on writing reliable and highly scalable back-end software.

    As in your example with http.Get, why would you assume that a non-200 response from an HTTP server should produce an exception? Yes, the .NET framework does it this way and I completely disagree with that approach. That’s not exceptional behavior at all, just a detail of the protocol. You *should* handle errors explicitly and figure out sane recovery paths rather than letting your application bomb out with an exception because you didn’t handle it.

    I agree, errors should be explicitly ignored if desired, never implicity. If Go allows one to implicitly ignore `error` returns, then this is indeed bad, but it shouldn’t deter you completely from using the language. Perhaps they’ll fix that “one thing” in the future. Have you registered a complaint at all? Or did you just decide to go and blog about it?

    • It’s not just 500 errors, if I disconnect my internet, http.Get still runs and falls through. The problem is a bit beyond complaining. the designers of Go have explicitly stated their position on the subject. I think there’s nothing left to do about it. Do you believe they’d mind my objection?

    • When exceptions are true first class objects like in Python then they work just fine in asynchronous code. You can easily pass them around and you can reraise them, even across processes. How does that make things worse?

      • I’ve never done Python. I was speaking from a .NET perspective where exceptions are tied with the implementation detail of a call-stack, which becomes more-or-less useless in an asynchronous execution context. Wrapping every `await` expression in a try/catch statement makes exceptions quite annoying to deal with, especially when you want fast execution and to not completely halt your thread just to unwind a call stack just to identify something that didn’t have to be an exception in the first place.

        I suppose it looks like I was casting the .NET concept of an exception onto Python exceptions, which I did not intend to do. I did note that I was speaking from a .NET perspective up front.

    • Python actually has a really decent framework for asynchronous development called Twisted and it handles exceptions just fine. As Roger says, since they’re first-class objects you can just pass them around and that’s exactly what Twisted Python does – exceptions are automatically converted to calls to special callback functions with the exception as a parameter. You don’t need to add a check to every single function call like in Go, you can install an error callback once and let it handle all the errors in a long chain of asynchronous calls, and if an error happens that goes unhandled Twisted prints out a warning. It’s quite neat really.

      • Also, multiprocessing catches and re-raises exceptions exactly because they’re first class objects. Unfortunately in that case, it takes some hunting to determine where the error comes from because the stack trace is skipped.

      • Yes, that’s great and all, but isn’t Python limited to executing on a single core still due to the global interpreter lock? You’ll never get full scalability there, async or not. Go gives you this by default without any such silly global locks. If my information is out of date or not applicable to all Python execution engines/environments, please do correct me.

      • @James Dunne:
        > isn’t Python limited to executing on a single core still due to the global interpreter lock?

        The GIL is irrelevant if your problem is I/O-bound. For CPU-bound problems the solution is either use Python as a glue language and implement the critical parts in C/C++, (like Numpy/SciPy) or use a Python implementation that lacks a GIL (the GIL is a detail of the reference implementation, not part of the language design).

    • What are you talking about? There’s nothing about exceptions that are preventing you from handling them on the spot. You can handle a non 200 http.Get result there, or you can let it automatically propagate up the call stack, and all without polluting your return data anywhere along the way.

      Moreover, the difference between “exceptional” and “non-exceptional” that the Go-folks draw seems to be irrelevant. If an http Get request returns 404, I want to handle it, and if I forget to handle it, I don’t want my program to continue chugging away on bad data–I want to be notified with useful information about the error’s cause. I don’t see why it would be useful to allow the program to scrape the 404 page when I think I’m scraping a 200 page. In most contexts, it seems your exceptional/non-exceptional distinction is useless in the worst possible way.

      Ada even includes exception handling, and it’s designed for mission critical realtime applications for crying out loud.

    • Your mistake is using asynchronous programming. God invented threads for a reason.

      Alternatively: complaining that modern error handling techniques don’t work for obsolete programming styles is kinda silly.

  3. I am not going to Go either but for different reasons.

    About the exceptions: You have shaken my belief that exceptions are evil (well, not necessary). But now, I must to reconsider the whole thing. For the time being, I would say that the calls to the 2 urls should be 1 call with a string in a variable, so only 1 after-the-call check.

  4. This concerns me very deeply, as well. What worries me more, however, is the crowd that has really started hyping Go as of late. This is the same crowd that hyped Ruby on Rails, JavaScript, Node.js and NoSQL in the past.

    Now several years on, many of us who aren’t in that crowd are now cleaning up the messes that have been left behind. They are not pretty messes at all. I fear that the same messes will again be left behind, but this time involving Go. This could be very damaging for Go’s reputation, and the reputation of anyone claiming to be a Go practitioner. That is why I am keeping my distance.

    • That’s a bit hyperbolic, Jimmy. Bad code is written in every language, including Python. There are lots of people cleaning up Django code, too. You may not like Rails, but Github is making serious money and solving real problems with it (I don’t know why I bothered singling them out, they’re by no means an anomaly) despite shortcomings in the language and framework. In fact, pick almost any language and there are people using it successfully in the “real world”. It’s ok if it doesn’t fit your programming style or match your aesthetics. That’s really what most language choices boil down to until you get to the enterprise, and then it’s the ability to commoditize the developer and the admin.

      • “Github is making serious money”

        Yea, but the struggled to make a profit. I think that was one of the (explicitly expressed) resons for accepting Microsofts acquisition-offer.

    • I suppose they are in a group of developers that is More Adventurous Than Me. That’s the kind of categories we all seem to like best. People who are Stuck in the Mud are Less Adventurous than me, and the people who Jump at NoSQL Faster Than Me, are officially nuts, whereas I alone, am sane, and well balanced. (grin).

      W

    • No way it’s they same group of people. I personally never used Ruby and don’t really like JavaScript or Node.js. I would almost say that the people hyping Go are exactly these that are not hyping Node.js, but that is just a speculation that I somehow observed at work.

  5. Hmm, I’m frankly disappointed that the HN crowd let such a misguided post make it to #1 on the home page.

    “Every single line requires an if statement to prevent programs from doing crazy things.”

    This is an absurd overstatement. I invite your readers to read literally any Go program ever written to see that this statement is the opposite of true.

    I appreciate Go because I’m working hard to become an engineer that builds robust software rather than a sloppy hacker that throws scripts together. One significant difference between the former and the latter is carefully handling errors versus not.

    Python’s error handling seems much more succinct only because most of us don’t both handling errors at all! Every other line throws many exceptions, but we ignore this.

    Bottom line:

    When I feel like having fun making something simple and getting it done _fast_, I use Python.

    When I feel like building anything that _needs_ to work, I use Go. And yes, that means taking error handling seriously.

    • One of the things that’s nice about exceptions is that you can catch them at different points in the call stack meaning that you can write code that basically defers error handling to the caller by simply not handling the errors. You can do the same thing in Go but you have to explicitly return the error to the caller which makes things look a bit messier and may have bugs when you miss passing along errors returned from other functions.

      Exceptions also crash your program if you don’t catch them. Error return values do not so you need to crash it yourself explicitly. Having the program crash is actually a desirable outcome in situations where an unhandled error occurs.

      Python programmers care about error handling. Go programmers do too but I don’t think Python programmers are just writing things “__fast__”. I gather that Go decided on this kind of error handling explicitly because of the concurrency features and I think you and the OP are comparing apples to oranges.

      • ‘Having the program crash is actually a desirable outcome…’ Yes. The purpose? To notify you to handle ‘unhandled error’, just like you said.

        Now you admit that you want to handle these ‘unhandled error’ and you are still not okay with explicitly handling these errors from the start? I found this argument self-contradicting and amusing.

        I think your argument is really about ‘return the error … makes things look a bit messier’. I understand this fully well: everyone likes shorter and less messy code. But that’s just human nature – it has nothing to do with what is actually right.

    • Why does the Go crowd (I generally like Go, mind you) insist that exception handling is somehow not taking errors seriously? If you encounter an exception, your program will fail on the spot rather than producing incorrect results or panicking many instructions later. And as someone who is learning Go, much of the code looks like this:

      result, err := somefunc()
      if err != nil {
      doSmthng()
      } else {
      doSmthngEls()
      }

      when it should look like this:
      somefunc()
      doSmthng()

      or (worst case):
      try {
      somefunc()
      doSmthng()
      }
      catch { doSmthngEls() }

      With exceptions, error handling takes place only where necessary. Feel free to provide an example of how exception handling isn’t “careful”. I bet for every example you provide, I can provide the same thing via Go’s error handling.

      Seriously, Ada is the most “careful” language I know of, and _even it_ uses exception handling.

      Moreover, Go allows a programmer to be careless and fail to handle an error properly, unlike exceptions.

      • ‘With exceptions, error handling takes place only where necessary.’

        But how necessary is necessary? I feel the only benefit Exception gives you is the laziness of being able to not handle some exception when you *think* it’s not necessary to handle. So in these cases you are basically saying: “Yes there might be an exception raised here, but I don’t think it’s necessary to handle it because I can’t see any exception just from my usage”. This is actually the predominant mindset for python programmers on the topic of error handling.

        When you write code, with your ‘modern’ exception and its flexibility of handling, do you *actually* go back to the source/definition of every function you used and make sure that any exception that can be raised is either handled or ignored because of ‘not necessary’? Because this seems like the right approach for exceptions, when you want to do error-handling seriously (or at least from those exception-lovers who claim to use exceptions seriously). Putting the question of ‘how necessary is necessary’ aside, what’s the difference of this approach from just handling the errors returned explicitly from the function (which with exceptions you even need to dig into it to see the list of exceptions)?

    • I grabbed a piece of go code lying around our shop. Lo and behold, pretty much exactly as the OP here described it.

      But, hey, congratulations on being a complete dick. Your mother must be proud.

  6. I just couldn’t like Go. It feels so inconsistent and awkward. Feels like curved baseball bat. A few examples of its inconsistency. Why leave out the ; and keep the {} ? I couldn’t understand that.
    Secondly, the weird names. What the hell is fmt? And why not println instead of fmt.Println() ?
    The for loop is also ‘old’. Even java has nicer looking for loops now, and in Java 8 will include iterators similar to those in Ruby. Why does Go insist in making thing so much like C (without being C and slower than C)?

    I found Go to be ugly, cryptic and inconsistent (syntax wise). For it to be successful it has to make developers comfortable and has to be fun to code in. Go isn’t. It might carve a niche in High Performance arenas, but it won’t be the language of choice for ‘regular apps’.

    • High performance arenas that think a garbage collected language is acceptable, rally aren’t high performance. Seriously. This is where I think Apple is on to something with ARC. I work for an equities exchange and we’ve replaced our Java components with C++ due to unacceptable delays due to GC pauses. We measure response times in microseconds, so any GC language is going to have problems.

      • Most people don’t work for an equities exchange and the nice thing about Go is not so much that it’s super fast, than that it’s “pretty” fast and compiles to a statically linked executable that can be deployed anywhere with one file.

      • Performance and guaranteed latency are two different, orthogonal measurements. In fact, you even can think of them as a tradeoff, as in algorithm design and in compiler optimizations you often can improve performance by sacrificing some latency and vice versa.

    • I just couldn’t like Go.

      It’s not like you tried.

      A few examples of its inconsistency. Why leave out the ; and keep the {} ? I couldn’t understand that.

      What is there to understand? ; is superfluous, because a newline does the same thing 99.9% of the time.

      As for {}, it is still needed if you want to delimit blocks any way you like. The other solutions would be significant whitespace a la Python (that a lot of people don’t prefer) or begin / end which is the exact same thing as {}.

      Secondly, the weird names. What the hell is fmt?

      A short way to write “format”, in the time honored tradition on programming shortnames?

      And why not println instead of fmt.Println() ?

      Because they want to it to be part of a package, not a special construct in the language or polluting the global namespace.

      The for loop is also ‘old’. Even java has nicer looking for loops now, and in Java 8 will include iterators similar to those in Ruby. Why does Go insist in making thing so much like C (without being C and slower than C)?

      Go has the same kind of for loops Java or Ruby has, in addition the old C-style for loop. Perhaps you should read some more.

      Really, those are your objections? Have you been programming more than 2 years?

      • > A short way to write “format”, in the time honored tradition on programming shortnames?

        Cryptic names may be traditional but they’re not a good thing: a better solution is to use tools that make it easy to work with longer names (the tool I use for it is usually NetBeans).

      • The biggest inconsistency is that arrays, slices, channels, maps are generic but there is no way to create custom generic data types. And map-keys a pretty strange, why not allowing a Hashable Interface with equals/hashKey. The thing is that Go is really practically but theoretically it “sucks”. There is only one reason generic data types were left out and why there are a couple of builtin generics types: Because generics ARE important, the authors knew that, but they were not smart enough to figure out a way to implement them efficiently so they picked the most important cases and baked them in, for-ever. So if one day generics are added, we have to deal with a probably slow map implementation and can’t fix it because operator overloading is not allowed. Overall Go is syntactically pretty boring and pretty inconsistent, nobody doubt that. But Go actually _works!_ pretty nice, and that’s why it’s so popular right now. Because most other language just “suck” at doing network! Yes, I’m looking at you, nodejs. All modern languages pretty much fucked it up with there non-blocking-callback-shit and async-await stuff like C#/python3.4 is not comparable to Go’s model. So we just have to live with it, there is just no real alternative for high-performance networking.

        @Garbage-Collection guys: Manual garbage collection comes at a cost, too. Go1.2’s GC is pretty fast and if you do not allocate, than there is no GC. So if you do your high-performance tests just allocate once and reuse objects. It’s not that difficult. And you aren’t getting realtime performance from either C++ and Go because most of the time you are not running on a realtime OS. Modern GC’s are way faster than usual memory management because memory is allocated/released in batches and often even reused. And hey, no more memory leaks or Segmentation faults 😉

  7. Hear hear – I’ve been making the same complaints about Go’s error handling on HN and not seeing an adequate response. Perhaps the best evidence is hello world – I’ve yet to see a Go tutorial that checks the println.

    Sometimes it is pointed out that exceptions can be done badly, which is correct. For example Java’s checked exception make life miserable. In C++ because exceptions are not ubiquitous they can’t be used safely. Lisp’s conditions are great. Python’s exceptions are ubiquitous and function well.

    Go had a real opportunity to get things right here, but they really screwed up.

    • Indeed. This article exactly words my reason for not go-ing with go. I really love the concurrency features, and have been hoping for a fast, compiled language without C/C++’s crufty syntax and unsafeness, but without the inherent verbosity (WidgetManagerFactoryDispatchers) of Java. Go succeeds in this, but the 70’s error handling really spoiled it for me.

      I know that exceptions can be abused, and aren’t suited for everything, but going back to old school “check the return value of every statement”, is NOT a solution that I like. It is not the golden bullet for safe error handling either, for the reason mentioned: easy to ignore, but also because it breaks the flow of the program, either by prematurely “return”ing or nested “if”s(), making it harder to see the whole picture / sequence.

      *Some* error handling verbosity (compared to say, Python) is fine, if it means that it is more explicit and statically checkable, but you shouldn’t be forced to Do Repeat Yourself every line. Go throws away the baby with the bath water.

      • If python’s hello world has a problem then you would definitely know as a user. With go you would never know. You do not have to catch every exception – they should not pass silently is all.

      • +1 to Roger’s response. Letting errors pass silently isn’t taking error handling very seriously, contrary to the claim of the Go-crowd (and I generally like Go).

  8. Pingback: I’ll Give MongoDB Another Try. In Ten Years. | Diego Basch's Blog

  9. Try it anyway. I find the lack of exceptions refreshing.

    If you study your examples closer, I think they in fact speak _against_ using exceptions in code. First, think about what error handling would look like with exceptions. Given your example above, code would stop. Abruptly. That’s not error handling. That’s just blowing things up.

    Then think about when things blow up. Would they blow up from a 404? Would they blow up from a 302 redirect? Should they? It’s impossible to tell from your code. That makes for software that behaves very badly when errors happen (and they do).

    If you want to handle your errors properly then, and spinkle your two line code with catchers and try blocks. That’ll do the trick. But then your code is far more unreadable then just checking return values. Error handling is hard. It doesn’t go away with some magic exception dust. I think the Go way is cleaner and more readable here.

    • > That’s not error handling. That’s just blowing things up.

      As opposed to letting things continue which would be _literally_ blowing things up. The point is exceptions prevent catastrophic results even if they should have been handled. Not so with Go errors.

      First of all, try/catch blocks are more readable, because you know at a glance that you’re handling an exceptional situation. You aren’t mixing error data with functional data. Secondly, with exceptions, you can wait to handle the error at the appropriate level, rather than having to explicitly return the error (continuing to mix functional and error data) at every level in between.

      Error handling _is_ hard, but it doesn’t have to be Go-hard. Exceptions make error handling obvious, clean, and much easier than the Go-solution. Go is demonstrably messier and more difficult to read.

  10. The subject by itself is nonsense. A good developer has more than one programming language in its pocket and chooses the right one for each project. I have never seen a programming “giving” up a language in favor for another one. You may learn a new language as an alternative for the existing one…

    • Unfortunately for your point, Go is marketed as competition to Python (I generally prefer Go, personally); however, if Go can’t successfully solve the same problem sets as Python, it’s unlikely to dissuade programmers. Therein, the subject is non-nonsense, and your reply looks silly.

      • Go was marketed as being a systems language (replacement for c/c++ etc. NOT python)

  11. > That problem is errors are handled in return values.

    I’m of the opinion that it can work. And it does work. In languages which are not Go mostly. Two examples I know rather well being Haskell and Erlang.

    First of all, it’s important that none of these two languages dogmatically shuns exceptions the way Go does (quite the opposite for Erlang, they’re used a lot… just in interesting ways). Now for the “erroneous returns”

    * Haskell uses tagged unions, the closest to what Go does is Either a b, with two constructors Left a (for errors) and Right b (for values). Haskell has a lot of tools in its box to make this sort of error handling pain-free:

    – the compiler can check for match completeness (that both correct and error cases are handled)
    – monadic operations allow using the “correct” value and letting the error go through without significant increases in verbosity or complexity (`fmap somefunc eitherValue` will apply `somefunc` to a `Right`, but will return a `Left` without touching it)

    * Erlang is much closer to go (or more precisely go is much closer to Erlang): Erlang functions tend to use tuples to return values an errors, explicitly tagging these tuples with the atoms `ok` and `error` e.g. {ok, Value} and {error, Reason}. Now this of course allows for case-based unpacking of both (as in Haskell), but it also allows for very terse *assertion of correct return*: one can use the assignment (actually a match) `{ok, Value} = some_call()` to get the returned Value out *and turn any error return into an exception*. Now of course, as in Go one can always ignore the return value altogether and not check it (this is common for IO functions which don’t return an actual value). But all in all, I found that it works rather well, it’s terse enough, quite clean and very explicit.

    • Explicit = fully and clearly expressed or demonstrated; leaving nothing merely implied.

      Ignoring return values is something we do all the time and I don’t find it very explicit when errors are ignored as return values. But then again I’m not familiar with Erlang or Haskell.

    • I forgot to mention the matching scheme when discussing Erlang and exceptions earlier, but it’s an unusual technique that I think works well when a function might or might not yield a value and either way it’s not exceptional.

  12. CLU, anciently, and Erlang both have exception-handling systems that work well. CLU has typed exceptions without the Java pain (because unhandled named exceptions are converted to a “failure” exception). Erlang is highly concurrent and has been used for some serious business.

    Joe Armstrong’s thesis
    [http://pubftp0.availo.se/pub/FreeBSD/distfiles/erlang-doc/r13b01/armstrong_thesis_2003.pdf] describes how to build fault-tolerant software in Erlang. He highlights the “fail fast” approach, and also explains why you should have few exception handlers in your program. One style used by Erlang is to distinguish exceptional things (actual or probable errors) from normal results. For example, a table search might have two variants, one that looks for something that might or might not be there (error return), and one that must find something that should certainly be there (because logic elsewhere was supposed to install it in the table) and raises an exception if not found.

  13. Hi! You should check D programming language out. It has all the benefits of Go(compiled, statically typed, nice to use, light weight threads – Fibers) and offers a lot more – powerful metaprogramming with templates and compile time function evaluation(CTFE), and you actually can go to the very bottom with pointer arithmetics and inline assembly.

    And there is a very promising Vibe web framework. It’s in its early days, but it already provides a lot of awesome features that take advantage of the goodness of the D – for example, thanks to the CTFE html templates are compiled to native code at compile time so they perform even faster than serving static files as it is literally writing stuff directly from RAM.

  14. I’ve been learning Go after a decade of Python programming (and before that a decade of C++ and C!)

    The error handling does feel like a step backwards to C. However what it does do is make you, the programmer, really think about what should happen for each possible error.

    With big Python programs you tend not to really know what exceptions can be thrown, and you often have to fix them adding a catch for this exception here and that one there after some time in production. Go makes you do that thinking up front.

    As a Python programmer I find it disappointing to see the result of fmt.Println or more importantly defer f.Close() not checked for errors in most Go programs. It would be nice if the Go compiler enforced checking the errors, or at least making sure you are deliberately ignoring them with the ‘_’ identifier.

    • “I find it disappointing to see the result of fmt.Println or more importantly defer f.Close() not checked for errors in most Go programs.”

      I read a lot of go code, and am not seeing this. There’s a chance I’m simply glossing over it. Where are you seeing it? Standard libs? Public repos?

      Citations appreciated, mostly interested in improving the status quo. Not interested in casting doubt or aspersions 🙂

      • I think the standard library is OK as it was written by a set of master programmers (I did check!).

        If you look at Effective Go for example, you’ll see `defer f.Close()` being advocated which ignores the error on the `Close()` method

        http://golang.org/doc/effective_go.html#defer

        Now most of the time it doesn’t matter if you don’t check for errors on `Close`, but if `f` happens to be a socket or pipe that you are writing to then it can give errors at that point.

    • In reply to your later comment, close won’t only fail on sockets and pipes – it can also fail for regular files and is often a point at which disk full errors are detected. The man page for close even has a section about how not checking the result is a common programming error. Python developers automatically get close checked for them due to exceptions while Go developers have to be extremely diligent and often aren’t.

    • > However what it does do is make you, the programmer, really think about what should happen for each possible error.

      Exceptions do that (they make it obvious if you aren’t thinking about every error!), and they don’t let your program continue when an error is unhandled. Furthermore, Go forces you to pass and handle errors along with functional data, when the two can be cleanly handled separately.

  15. My major complaint with go is how unused variables/packages always throw compiler errors that you can’t bypass and an utter inflexibility among developers to consider giving a compiler flag for these debugging purposes (even something obnoxious like `–unused_generates_warning_not_error`). See:

    http://golang.org/doc/go_faq.html#unused_variables_and_imports
    https://groups.google.com/forum/#!topic/golang-nuts/OBsCksYHPG4/discussion

    I like the fact that unused variables/packages throw an error if declared/imported but not used. However, if every time I comment out a section/function call during debugging, I have to make sure that I comment out any imports/declarations before rerunning its a needless waste. Or worse they suggest in the FAQ, to write no-ops statements like `_ := some_package.Function` to silently disable the compiler error. That suggestion is absolutely the wrong solution, as you can easily forget to remove the no-op statement which can permanently disable the very sane check.

  16. I read a lot about Go. There are lots of good ideas in Go, and the other languages should get some inspiration from Go.
    At first, the lack of exceptions and generics really put me off. But I still did the full tutorial, I tried to write some code.
    Then, I read more on the opinions of the people who created Go, and I got more insight on how they don’t miss such basic features of modern languages.

    Unfortunately, it was not enough. This cannot work for me.
    When something unexpected happens in my code, it’s mandatory for me to have the error unwind until it gets to some UI where the stacktrace can be shown to the user, without crashing all the program. Exceptions work for this; error codes just don’t.

    About generics, well without them you have to cast every item out of any collection you use. Even Go had to give in and offers a generic array and hash table, else it would be so annoying.
    Congrats anyway for getting as far as one language can go without proper support for genericity.

    So, no Go.

    • I actually read that article before this one, and no, it doesn’t make any good points. It makes a lot of unsupported or illogical arguments (“exceptions are bad because sometimes people don’t use them properly”–go doesn’t prevent this either, “exceptions pass the error up the call stack”–where it should be handled, “go takes error handling seriously”–like letting an errant program continue silently toward a cryptic panic or incorrect result, “some languages don’t do exceptions well”–not a criticism of exceptions, but of poor implementation).

      I have yet to see a valid argument against exceptions.

      • here a valid argument against exceptions:
        There is nothing can you do with an exception, except print a nice error message and exit. And there is nothing can you do with an exception that you cannot do with exceptionless language.

        Example: during a long computation, you reach a “Division by zero” condition, so what can you do with an exception system … nothing. In fact your code is cleaner and simpler if you check before the division.

      • Unfortunately, “unsupported or illogical arguments” seem to be the BIGGEST single failure of the Go community. Take, for example, these discussions:

        https://groups.google.com/forum/?fromgroups=#!topicsearchin/golang-nuts/group:golang-nuts$20AND$20subject:Decimal/golang-nuts/1w9daeTwXeM

        https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/KH9KysfS5HQ

        Childish arguments, beating worthwhile contributors down. The guy was just trying to make a library that would allow him to do some handy physics expressions, as he can do in python already.

        And there are many repeats of those discussions, with similarly uninformed, hateful beating down of would-be users/contributors.

        There ARE some nice things about Go. However, is this REALLY the language and community that you want to be betting your business/career on? Not me.

      • @J Lemire: You no not of which you speak.

        I do use exceptions for things other than printing nice error messages. I have an RPC server. After getting down in the bowels of the stack, I find that the client sent me a badly formed request. I can now “raise MalformedRequestError”, popping back up to the level where I received the request. I can now package that error up into the response with an error number and a textual message and return that to the client.

        I did not have to return the error up through my stack call by call. I only have to deal with the error where I detect the error and where I package the error for consumption. I thus did something with the exception that you cannot do in an exceptionless language.

        Checking if you will divide by zero is useful if you can do something useful other than returning an error.

  17. This is a really bland post. The poster won’t use Go because of some admittedly presumptive objections about Go’s error handling. In preference to Go, the poster prefers Python, a much slower scripting language that has exceptions. Fine. If exceptions are that exceptional, stick with Python. Python’s great. As for me, I just finished my last two Web projects with Go. These were projects that normally would have called for Django, my previous go-to Web framework. For one project I did use the mgo mongo driver, and for both projects I used the gocheck testing library. Other than those two “outside” packages, the projects were built entirely with Go. No Django, no virtualenv, no pile of pip packages. Just Go. For templating I used Go’s html/template, a standard library package. And the apps are fast.

    Still, I can see that Go isn’t for everyone. It would probably help to have some reasonable familiarity with C in order to appreciate some of Go’s subtler points. And if you’re not interested in concurrent programming — that is, you’re building fairly straightforward Web apps satisfied by Django’s (or Rails’) gotcha-covered stack or Flask’s (or Sinatra’s) simple file-piles, for Nodejs’s Javascriptcentricity — then you’ll be less likely to appreciate the toys found on one of Go’s cooler playgrounds. And why would you? But this is where the problem comes up, because Go isn’t simply a drop-in replacement for Python or Ruby or whatever. It’s a different and very powerful tool that can, absolutely, fly around in Pythonspace, but which also can do some things that, quite frankly, Python or Ruby can’t do nearly as fast or as well, exceptions be damned. If you’re usage doesn’t call for those things, then you’re missing nothing.

    • 5 years of my life I’d spent writing C for a living. Both Go and Python are different tools for different jobs. I think for me, Go could have taken care of a lot more of the problems I use Python for if only it had embraced a different error handling model. That’s all.

    • I love Go. I think much of it is great; however, I’m not going to pretend that letting an errant program chug along silently is a good idea. Go error handling is a half baked idea. The arguments against it are based on specific implementations, improper uses, or some misguided idea that mixing error and regular data several times per function is somehow a good idea.

  18. I thought twice about leaving here a comment since I don’t know Python nor Go. I won’t defend either’s error handling but I wish to call your attention for the third option of handling errors: Design by Contract (DbC). For me, what’s more interesting about DbC is this: you can either say your program is using DbC or you can say your program isn’t. There is no way you can escape it once you are in the mindset of it, you can’t fool yourself saying ‘I’ll patch this later’. Also, note Eiffel language is the one who truly implements DbC. It seems all libraries implementing it for other languages fail at some point to convey the thoughtfulness of Eiffel’s DbC.
    P.S.: FYI, I’ve heard Eiffel’s support for multi-threading is safe but not very efficient internally.

  19. Recall the “Ariane 5 flight 501 failure report”, regarding a very big rocket that exploded because of an Ada exception (overflow in float64->int16 conversion) that developpers has forgotten to handle. As a result, a navigation computer sent a stack trace to an engine controller, which interpreted the gibberish as a command to fully deflect the nozzles of the main engine and solid-fuel booser rockets, with catastrophic results.

    http://www.di.unito.it/~damiani/ariane5rep.html

      • Yes, and Go errors are much more likely to go unnoticed because they can continue chugging along toward an incorrect result. Moreover, Ada can compile without exception-handling if you really believe silent failure is a better alternative.

    • Feel free to explain how failing to handle this error in Go would have prevented the rocket from crashing. No, exceptions don’t prevent all mistakes, but they go a lot farther toward preventing them (and producing clearer code, and making errors more obvious, etc) than Go’s solution.

      • Off the top of my head I’d say what if the code throwing the exception wasn’t mission critical and could have thrown out bad data that would be corrected on a future iteration. The data might be checked for tolerance somewhere else and discarded before its used. Letting the error go unhandled in Go might have saved the rocket. This might be what the Go authors mean about thinking about errors though they said you shouldn’t let one go. Maybe you should check your data instead of counting on an exception somewhere else to bail you out.

        I think this example really makes the case for Go. In fact for the first time I actually understand the argument of exceptions being lazy. Don’t count on exception handling to validate data. If you validate then a missed error doesn’t hurt. But a missed exception can kill your program in a scenario where there is no chance for a restart. Does this make for more code/”ugly” code? It might. But its lazy to think “well if I miss some of this at least the app will crash” which seems to be the mentality here.

  20. OMGERD!!!

    _ := mygergaderkaderk()

    1.) You dont have to handle errors. Its smart too (consider the fact that your returning an error interface and thus can create custom Errors however you want.

    If err := fml.ThisFuncIsAWasteOfMyLifePleaseGiveMeMoarTryCatchPLZ(); err != nil {
    return err
    }

    is seriouly the reason why you dont want to use Go, then…. We dont care. If you are going to troll Go, atleast find a good reason. (good luck on that)

  21. How about Scala ? It’s a nice OO language with full functional paradigm (important for concurrency) running on JVM. A course is currently going on Coursera.org with its creator Martin Odersky presenting it. A must view !

  22. Urgly expcetion handling is one of the most reasons that make me dislike python. When progamming in python, I always worry that some unexcepted exceptions will pop up and startle me. So I make up my mind to stay away from python as possible as I can.

    • If exceptions startle you then what are your feelings toward ignored errors that cause sneaky bugs which require debugging the entire application codebase?

      • By the word “startle” I mean I find it hard to expect what exceptions a function will throw, because the children functions called by this function also throw exceptions. But by checking the returned errors, every thing is under my control.

      • @stevewang Java requires functions to explicitly state the exceptions they might throw. How often do you check fmt.Println for errors? Before this conversation, I didn’t even know it could produce errors.

    • Yeah, ignorance is bliss. Go won’t tell you when you hit an error unless it leads to a panic. With Python at least you’ll find out when you hit an error. Exceptions make it a lot harder to make errant computations.

  23. I started using Go about a year ago, for a hobby, and it took me writing a few things to get comfortable with it’s differences, like error handling. Fast forward a year and we’re now using Go in production at work. We are diligent on our error checking, and our code doesn’t look scary at all, and even cleaner looking than a try/catch|except with numerous catch|except lines.

    We’ve just finished an application that does some fairly heavy concurrency. We’ve had no problems getting errors from our concurrent code (using channels) back up to the main logic. Best thing is that the code, for being so concurrent, isn’t intimidating.

    We also use lots of Python as well. Go wasn’t a `replacement` for use, just a different tool we can leverage; we use it where it makes sense.

    Write some real code in Go, then base your opinion on the experience.

  24. This thread is well-aged, but I’d like to add something. When I started on Go, the reason I fell in love with its error handling style is because of the blatant exception abuse I see in C# every day. For me, it’s not “how SHOULD exceptions be used” but “how do they end up being used in many code bases.” We can blame bad programmers for these issues, but the fact they happen so often makes me feel we can consider a different approach. Now, my real-world-hell examples:

    – Invalid form input from web layer to BLL-type layer. Validation fails, programmer throws exception. WTF? How do I know this thing will blow up my web app on bad input? Sometimes VS intellisense reminds me, often that’s not documented. (BTW, I hate VS, but that’s another rant).

    – Some smartass decides they need to handle exceptions. Every layer of a data call (Web -> BLL -> Data) has a try/catch/finally in it. First, this is verbose coding. Second, if you don’t know how to properly throw the exception up, you kill the stacktrace. Third, if you don’t throw the exception we either hope you returned some meaningful value and logged it, or we’re really screwed. Fourth, when I call something that returns a data value or ID or whatever, I have to now check if that ID is valid. So I put some if (model != null) or or if (id > 0) and we’re doing it Go style anyway.

    Again, I know these practices may not be the intent of C# design, but they happen. A lot. I have to litter my high-level code with try/catch then decide what each exception means to me, which isn’t easy.

    So I found Go and saw that it prevents this bullshit. I love it. I’m hearing the arguments here and I appreciate their validity, but I think some of this is people just don’t want to change.

    One more thing: to the complaint that Go uses {}. Please. Python’s tabbing seems so cool and clean until you have to share code with someone who uses a different tab/space scheme, platform, copying from the web or something. Not so fun then.

  25. You might want to try:
    http://blog.golang.org/2011/07/error-handling-and-go.html

    Which looks a lot better than the general try catch (maybe) that goes around. Go is funneling you towards this style of error handling, not the 1970 C style rut which you immediately fell into.

    I’ve had it with runtime languages who’s debugging technique is “write it correctly the first time”. There are huge learning curves associating with jumping into these code bases mid project, debugging tools haven’t kept up with these high level languages or at least not enough people are using them, and then there’s the joke of “writing unit tests to test your runtime” which get turned off mid project because they just don’t work anymore.

    Yeah, I’d rather take some more time at the beginning thinking about how I want the error framework to work out than try/catch until the end of time.

    • I quote and reply to that link in this article. Specifically the subtitle “Simplifying repetitive error handling” just shows another example of repetitive error handling. It’s just that every error-returning function has to be wrapped in “if” and “return” if you want your code to be reliable. Yet the wrapping isn’t even mandatory in some cases.

      • I’m accustomed to error handling like this:
        https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/scsi/scsi_error.c#n239

        I also am a rubyist and am forced to code python.

        In this example, handling the protocol with exceptions would be silly, because the events are not exceptional. Exceptions are abused on a regular basis. I’ve lost count of how many times I’ve made small try blocks, caught only the general exception, and addressed the most likely error. It’s not because I’m lazy, it’s because the documentation isn’t efficient (or poor) combined with the cost of testing the additional exception. e.g. the curse of interpreted code, did I even code my error handling correctly?

        How about exception handling like this?

        # Write the adminsettings
        connection = MySQLdb.connect(user=user, host=private_address, passwd=password, db=database)
        cursor = connection.cursor()
        do_install = None
        try:
        # Try to create the “mediawiki_juju_setup” table and if its already there, skip some things
        cursor.execute(“create table mediawiki_juju_setup (id int)”)
        do_install = True
        except Exception as e:
        # If we can’t create that table, it has likely already been initialized
        print ‘Could not create mediawiki_juju_setup: ‘ + str(e)
        do_install = False

        Where’s it used as a control framework. There’s no disagreement here that the author should have actually checked if the table to exist to begin with before acting right? This is *average exception use* I see, because people won’t take the extra time to figure out how the method works so they use the exception side effect to control code.

        C has taught me that robust error handling can be yours if you commit to organizing your error handling, perhaps even delegating a task to it.

        Commit to the go paradigm and you might actually surprise yourself. If you don’t commit then the language isn’t for you.

      • I’m accustomed and tired of C error handling. And I’m not saying all API’s should be exception based. What I am saying is:

        1. Having only return value based errors causes boiler plate. Perhaps macros can alleviate this problem.
        2. Not forcing the dev to check every error returned promotes errors passing silently.

        In your MySQLdb example you’re showing what you think is a bad use of exceptions. We can talk about the frequency and severity of exception abuse vs errors passing silently and boilerplate. Your mileage will vary depending on what you’re programming. Please see http://www.yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html

  26. One of the reasons I like Go is the LACK of features rather than its feature set.
    Its not a Kitchen sink language. If you cannot live without try /catch block all over your
    code then that your preference. I love that fact that Go authors kept the feature set to a minimal to make the language an absolute pleasure to code in. All other languages seems complex compare to the beauty and simplicity of Go code. The secret of a cool new language is to keep it small and simple to its fun to code in!!!!
    That my choice of server language. I use Java on Android for client and wish I could code in Go on the client as well. I love the clean syntax and runtime performance of Go!!!!

    • Go’s approach to error handling is rediculous for a 21st century language (and reminds me of curmudgeonly developers who insist on wrapping code to 80 characters and won’t use word wrap), but it’s still a huge improvement over C++ so I’ve enjoyed using it. Exceptions can be messy, especially when you are dealing with so much concurrency, but anything would be better than this system where you ignorantly ignore some exceptions and then others get manually shuttled back up the call hierarchy, destroying the call stack in the process. For my go code I generally use the pattern func check(e error) { if e != nil { panic(e.Error() }} around every system library function call (unless it’s the unusual case where I am actually handle the problem).

    • If you’re interested in simple languages, I would suggest that there are at least two languages that leave Go in the dust in terms of both simplicity and beauty: Lisp and Forth. Well, maybe not always in practice: Common Lisp is a pretty complicated language, so you would be better off looking at Scheme (although even Common Lisp is simple at its heart).

      I’d throw in Smalltalk and Prolog as other potentially simple and beautiful languages, but I don’t have experience is using either.

      And for the record, I really wish I could use Common Lisp on Android…

  27. Pingback: Empezando con golang | atusell::

  28. I agree with the author. Writing compound-if statements over every function call in Go gets old really fast. There is a reason that exceptions were invented. Just because bad-code bases/bad-libraries abuse exceptions is *not* a reason for getting rid of a valuable language feature. A library that does exceptions correctly: well-designed exceptions following a exception hierarchy produces elegant, testable and readable code.

    Also no generics = lots of boiler plate code for algos/collections, but that isn’t the scope of this post…

  29. It is simply bullshit that exceptions in Python let you handle errors in a better way. Actually when you see a function in Python, you have _NO IDEA_ if it can throw or not. Now if you just put catch Exception somewhere high in the call stack, it prevents your program from crashing, but the error is by that time completely not local and you have anyway no idea what happened, so it helps nothing.

    With Go, when I see that a function can return an error, I always check how it can fail, I never silently ignore errors. It’s just a myth that errors get ignored in Go. It’s not Go that is ignoring errors, it’s careless programmers. And the point is that you always know that a function can fail in Go, not so much in Python, unless you preventively read all the API documentation…

    • And actually the fact that Go is checking if you are actually returning something from a function if you define so is also quite nice. How many times have I seen Python code retuning None somewhere accidentally, crashing later on calling a method on None? Go at least forces you to type “return nil” and makes you think if you really wanted to do that…

      • It doesn’t force you, that’s the problem.
        It shifts even more burden on the developer. Who is a human and where a mistake is syntactically possible (not checking an error), humans will make that mistake many times.

        You gain static type checks (not a new idea), but they took 3 steps back with losing generics, an outdated type system, and error codes passing silently (should always crash on default, because people inevitably make mistakes).

    • I generally have a pretty good idea as to whether or not a function call can raise an exception. I can trap exceptions at a low level when they happen, wrap the exceptions into my favorite framework for the program that i’m working on, re-raise them, and then catch them at a high general level where I can pull out all the nitty gritty details that need to be exposed to a user.

      • Looking back on my experiences with C, Ruby, Python, and now C++ *without using exceptions* I have to admit I prefer a language without them. Getting your head around a new API and using it well is enough of a challenge, then you get to learn the error path runtime that is conditionally creating all sorts of stuff as it unwinds the stack. I’ve done both, I’ll take the error code/return approach. With modern code completion plugins you really shouldn’t be writing much repetitive code to begin with. I know I know, “C++ is evil”, take another look, it’s changed quite a bit from when I too held that opinion. At least here, I get the choice of using exceptions based on the frameworks I use etc. In Python, exceptions are the norm… which doesn’t make them exceptional.

  30. Pingback: pathoc: break all the Python webservers! | iSEC Source

  31. I’m not really qualified to talk about exceptions in terms of performance or concurrency. But in terms of straightforward single threaded applications, a lot of people here are just obfuscating the very straightforward advantages of exceptions over error codes.

    1) Exceptions cannot be ignored. A lot of people are getting this backwards: that error codes force you to check them. They don’t, any more than exceptions force you to wrap everything in try catch. But when an exception is thrown, it will crash your program if not handled, which is preferable to it continuing silently.

    A common example: I import some code that someone else wrote. I have complete control over its inputs. My code design is such that I should never put the imported code in a bad state. So I do not do exception handling/error codes. Then I run the code, and in fact it does go into a bad state. Maybe my code is buggy, maybe I misunderstood the usage. With exceptions, it crashes and tells you exactly what happened. With error codes, it chugs along silently, and I can only prevent this by checking the error code. Hence your code is either littered with annoying checks, or fails silently. Exceptions offer a way out. They basically combine assertions (crash if condition not met) with error codes (wait, don’t crash, do this instead).

    2) Exceptions (unchecked) propagate up the call stack. Suppose you ask the user for input, and upon input it calls a function, that calls another, and so on, until you are at stack depth of 20. f20, the top of the stack, finds out that it cannot perform some low level procedure like opening a file. f19 is a slightly less low level function. It is just trying to do something, using a file. If the file is not there, it has no idea what to do. If f20 throws an exception, this will pop all the way up to f1, which can inform the user that the input is bad, and request new input. With error codes, you will need to handle the error code and pass it at every single level. This adds 18 if checks.

    I really don’t understand peoples’ objection to exceptions in favor of error codes.

    • > “I import some code that someone else wrote.”

      Perfect. With Go, that code will have clearly defined exit points even when an error occurs, making the code easier to understand. In the case that there’s an error, it *is* your job to handle it. If you want to handle it by crashing the program with a stack trace, it’s trivial to do that in Go. Or you can recover and log the error message, or log the stack trace, or do whatever is appropriate.

      Ignoring the error and letting it “chug along silently” is, in my opinion, not an option. While Go gives you enough rope to hang yourself, that doesn’t make it acceptable.

      Yes, that means writing more code. It’s annoying, until it becomes an unconscious habit, but it’s not hard.

      The alternatives are writing lazy exception-based code that blows up when something goes wrong, or writing good exception-based code, which is typically harder than acknowledged and few people get it right.

      > “I really don’t understand peoples’ objection to exceptions in favor of error codes.”

      At the end of the day, I think there are pros and cons to both and it becomes a matter of personal preference. For me, explicit error handling encourages me to consider errors before they become catastrophes; it’s a small up-front investment that (IMO) leads to more reliable production code. The default approach with exceptions seems to encourage ignoring errors until they happen, which works out fine in practice for many applications and saves you some time up front.

    • How about handling the error from the start with explicit error return value instead of patching things up again and again when you wait for your program to blow up in fear?

Leave a reply to weberc2 Cancel reply