Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> If I could get out of the 1970s and use an editor other than vi, maybe I would get some help from an IDE in this regard, but I staunchly refuse to edit code with any tool that requires using a mouse.

So you've shown that Go is appealing to rigid curmudgeons. Personally I'm still hung up on the "every function (edit: that does anything which might itself return an error code, which in large scale code is quite a lot) must return an error code" thing. Just like not understanding the purpose and usefulness of graphical editors, the creators of Go seemingly (despite their legendary status...) seemingly not understanding the purpose and usefulness of exceptions (waving them off as "they result in convoluted code" with no explanation) is keeping me pretty skeptical.

It just requires I take in some well written, idiomatic Go code so that I can finally "get it", how I'd live without exceptions, but I'm too busy being productive in Python (and enjoying Pypy's ever increasing speedups) to get that interested.



It is not the case that every function most return an error.

The Go creators do understand the purpose and usefulness of exceptions. They chose not to use exceptions with this knowledge. See http://golang.org/doc/faq#exceptions for their reasons.


I don't know. The quality of this FAQ entry is in my opinion narrowed by their inclusion of FileNotFoundException, which it seems they did not understand. The use case for this exception is not to allow lazy programmers to use it instead of checking that a file exists, but to signal to a programmer that his world view of the state of his program may be wrong despite his best efforts, e.g.

  if(file.exists())
  {
    //do something
  }
There's a race condition between the if and do something which invalidates the programmers world view (someone can delete the file between these two statements). And this is an exceptional situation the program has to deal with. Error codes may tell the programmer this, but it is quite likely that the programmer will just ignore it, because "I've already checked that it exists - what could possibly go wrong?". Exceptions, especially checked exceptions (in my opinion the only good exceptions for "normal" program code)(1), force the programmer to deal with this problem. Or to say - deliberately - "Hey, program, I don't care for the stability of my software. Just explode if this happens!".

(1) Languages which have only unchecked exceptions do, in my opinion, cave in to the laziness of programmers: "but, but, it is so much WORK to deal with all of this. Can't it just go away? Please?" - the result is code which can explode everywhere. This is even worse than no exceptions. With return codes you know at least that you have to check the code yourself very, very carefully all the time.


> There's a race condition between the if and do something which invalidates the programmers world view (someone can delete the file between these two statements). And this is an exceptional situation the program has to deal with.

It's not an exceptional situation. It's a bug in your program. And it's not lazy to open() and check for existence. It's actually the _only_ sane way to check that the file exists, if you plan to open it.

> Error codes may tell the programmer this, but it is quite likely that the programmer will just ignore it, because "I've already checked that it exists - what could possibly go wrong?"

The following code is obviously wrong because of the race condition you mention. Nobody in their right mind would write code like this.

    if exists(file) {
        f = open(file)
        // do something with f
    } else {
        // handle "file not found" case
    }
This code is correct, to some degree:

    try {
        f = open(file)
        // do something with f
    } catch (file not found error) {
        // handle "file not found" case
    }
As is this Go code:

    f, err := os.Open(file)
    if os.IsNotExist(err) {
        // handle "file not found" case
    } else if err != nil {
        // handle any other error that might arise
    }
    // do something with f
The thing is, the above code is not me being extra careful about checking errors. It's just bog standard Go code. Checking error values is the only way to write even half-decent Go code, so everyone does it all the time.

No reasonable programmer would write Go code like this:

    _, err := os.Stat(file)
    if err != nil {
        // handle "file not found" case  
    } else {
        f, _ := os.Open(file)
        // do something with f
        // (or explode if file doesn't exist)
    }
To my Go programmer eyes, the underscore (where I'm ignoring the error) in the os.Open line sticks out like a sore thumb. You wouldn't write it, and when reading you would certainly notice it as bad code (or at the very least extraordinary code).


Go basically does have exceptions, though they call it something else, it is slightly less powerful than you would normally expect, and the idiomatic usage is very different.

Honestly I that Go's idiomatic usage of panic/recover is a good idea even in other languages. Exceptions passing package boundaries is typically a pain in the ass in practice, it makes for ugly code.

(My "day job" is typically Java these days, some Scala. I am not speaking from inexperience like many Go detractors like to assume. There seems to be a perverse notion that anyone who dislikes exceptions must not understand them. Silly.)


Go doesn't require all functions to return error codes, and Go has exceptions (called panics).

In Go, conventionally, the publicly exposed functions in a module shouldn't usually panic but should use error returns to report unusual conditions. But that's a convention to keep the behavior of functions clear from the interfaces, not a language limitation.


The language has panics. But you aren't supposed to use them. So...


Of course you are supposed to use them when appropriate; they have their uses just as goto can have its valid uses. The implementation of the standard library contains some examples. But they should be used judiciously and not for mere error handling and not across package boundaries.


> The language has panics. But you aren't supposed to use them. So...

Not true. Panic/defer/recover is there to be used. But panic/recover should typically be internal to a package and/or used in a situation where the program itself suffers an error; not because of faulty user input/validation/etc.

Edit: What mseepgood said!


> The language has panics. But you aren't supposed to use them.

Conventionally, you generally shouldn't use them in a way that crosses the public interface of the module in which they are used.


http://golang.org/doc/faq#exceptions

A function isn't required to return an error code, but if you plan to deal with errors, it's the easiest way to do that.

I think the Go creators understand the purpose and usefulness of exceptions, they just chose to not implement them in favor of other approaches which work fine, of course, it's a matter of taste, as with almost any "language difference" argument. If you get real hung up on these differences, one might argue that you are the curmudgeon.

I didn't find learning/implementing a service in Go to be terribly challenging, even though I translated an existing Python service to Go. There were frustrating caveats that I had to work around because of some of the great things Python does, but over all the benefits of doing it in Go paid off, and it's about getting something for your time/effort.

Your last argument is totally legitimate though, but it's hard to say what would help you "get it" by throwing random bits of code at you, it's really something that you have to care about, spend the time to dig into, and make the realization for yourself. It may never happen, and as long as Python does everything you need, of course you'd have no incentive to use Go.

There seems to be a common theme (generally speaking) on HN that after the front page reaches some saturation on a particular subject, people start being very critical of it, not on its merit, but because it is taking up space where they expect to see a diverse set of content. I can sympathize with this, but I think it's best to try to dig for the value that others seem to be getting out of things, rather than sighing at the constant cheers of others, just my opinion though.


Don't confuse not understanding something with understanding it and thinking it is a poor idea. The Go authors understand exceptions perfectly -- they just thought that it was a bad idea: http://golang.org/doc/faq#exceptions


yes I've read that and their reason is "it results in convoluted code" - which is not at all my experience, programming in Java and Python for many years, it's worse in Java for sure due to the heavy emphasis on checked exceptions, but in Python they are a dream. "It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional." also not true in my experience. I really disagree with the notion of hobbling a language just to prevent beginners from writing bad code. Beginners will always write bad code no matter what. I'm not a beginner, and I really don't need to be denied useful tools just because beginners will misuse them - I mean we're talking about improving on C/C++ for chrissakes, in the hands of a beginner those languages are like nuclear weapons. This particular FAQ entry makes it seem very much like the authors have just not seen exceptions used effectively, which I find kind of astonishing.

I watched Bruce Eckel's talk at Pycon, "Rethinking Errors - Learning from Scala and Go" (http://us.pycon.org/2013/schedule/presentation/52/) and I was so ready to be converted. But his arguments were pretty unconvincing.

Can't someone just make this case convincingly?


Go's error handling model has nothing to do with schooling beginners. In fact there are several rough edges in Go that make sense for experienced programmers, but are difficult for newcomers to understand. (The distinction between the new and make functions is one example.)

The reason Go does not have exceptions is because, on balance, they make the language more complex without actually improving the code you write. I have seen countless A/B comparisons, and it seems that if you want robust error handling, it's going to be relatively verbose regardless of the approach you take.

To handle errors well requires your attention. Error handling is at the core of what most programs do, and it should be visible. In Go, errors are a computable value that you handle using the same control flow as any other value in the system. It shouldn't be relegated to a side channel that must be managed using separate, often invisible, control flow mechanisms.


I think a lot of people HAVE made the case convincingly, at least well enough for me. I have worked in major C++ shops that ban the use of exceptions (and enforce it).

Just to add another person who regrets exceptions to the big pile, http://250bpm.com/blog:4 (The ZMQ Author)

"Thus, the error handling was of utmost importance. It had to be very explicit and unforgiving.

C++ exceptions just didn't fill the bill. They are great for guaranteeing that program doesn't fail — just wrap the main function in try/catch block and you can handle all the errors in a single place.

However, what's great for avoiding straightforward failures becomes a nightmare when your goal is to guarantee that no undefined behaviour happens. The decoupling between raising of the exception and handling it, that makes avoiding failures so easy in C++, makes it virtually impossible to guarantee that the program never runs info undefined behaviour.

With C, the raising of the error and handling it are tightly couped and reside at the same place in the source code. This makes it easy to understand what happens if error happens..."


That is a problem with the way exceptions work in C++, not with the exceptions as concept.

C++ exception's design suffer from being added to the language in the last years of the language's design and having to support the possibility of being turned off if desired.

This, coupled with the manual resource management of the language is with lead to some of the issues with exceptions in C++.

Not all languages with exception's support suffer from the same problems.


If you think exceptions are the right way, you can use Go's exceptions (called panics). Whatever they thought about the desirability of using exceptions, its not like the creators of Go didn't build them into the language.


If I'm going to use Go, or any language, I definitely want to use it idiomatically.

Don't fret, if this were eight years ago you'd have seen me railing on significant whitespace. And we all know how that went.


> If I'm going to use Go, or any language, I definitely want to use it idiomatically.

Idioms evolve, and they evolve because they are challenged.


fine, but I've learned enough languages to know that the absolute worst thing you can do when you start out with language Y is make it act just like your previous language X. It's a very natural instinct for almost everyone (just read "Python is not Java" for an example), but for at least the first year or two of using a new language I think you have to do it as idiomatically as possible, before you have any insight into how to challenge the designer's idioms.


> fine, but I've learned enough languages to know that the absolute worst thing you can do when you start out with language Y is make it act just like your previous language X.

Sure, if you want to learn the idiomatic Go way of doing things, you do things the idiomatic way. Once you've reached the point where you have familiarity with the idiomatic way and have a reasoned analysis of why you believe the idiomatic way is wrong (at least for you doing the things you want to do with the language), that's no longer the case.

If you reached the point where you feel comfortable arguing that the idiom is wrong, you've should also have reached the point where you can use the language constrained by features, not by conventional idiom.


One might also note that Google doesn't use exceptions in C++, either.

http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...


Most of the arguments against exceptions presented in that document apply specifically to C++, particularly in a codebase with a large amount of exception-unsafe code (which is a C++-specific problem).

"On their face, the benefits of using exceptions outweigh the costs, especially in new projects...Things would probably be different if we had to do it all over again from scratch."



The joke goes, "If every other line of code you write starts with 'if err != nil', you might be a Go programmer."


No, we can just see the "if err != nil". It's still there in Java or Ruby or Python, lurking in the notional space between the lines and waiting to branch to an exception handler you installed in the caller's caller's caller.


Same in Go, because of panic and recover. For example, "foo.Bar", if foo is a nil pointer, can invisibly branch to an exception handler you installed in the caller's caller's caller.


Can but idiomatically, usually does not. In most code, that would behave like a segfault with a more helpful crash log.


That is exactly because of those type of developers in the industry that the latest Bret Victor's talk is so interesting

http://vimeo.com/71278954

Basically he goes on to show how many people still code like the 70's instead of adopting languages and paradigms that were already possible in late 60's systems.


i hate watching videos but yes, this is really interesting - von neumann: "I don't see why anyone would need anything other than machine code". I deal with the resistance thing a lot in my work with ORMs, I should integrate some of this into my writing.


I was hung up on error as return instead of exceptions but came in terms eventually. Now i think, compared to exceptions the error handeling is better off with go's approach. They are local, and require more concious effort. Specially while coding for the critical systems this helps as you are not passing the buck to some other section of the code.


There's no requirement at all that functions return error codes. If a function can't fail, or if you don't care about if it fails, don't return an error.


Exceptions are just glorified gotos. The longest single time in my life chasing a bug was because an exception was firing somehere down udner and nobody noticed, because it was kind of part of the logic but a fringe case.


this is a thoroughly debunked argument that Joel tried to make. Unlike goto, exceptions have stack traces, so when used correctly, their source and propagation are immediately obvious and traceable. An unreported exception in your buggy program is certainly no worse than an ignored error code.


The exception was catches somewhere It formed an unexpected, rare execution path that nobody could think of. It was not detectable by reading the local code. A missing error return would have been.


inappropriately catching and ignoring an exception is the same as ignoring an error return code, deeper down the call stack and not in the code you're looking at. the difference is, catching and ignoring the exception requires that it be actively done, whereas ignoring an error code is the default if no action is taken.


You have a point. I'll think about it ;-)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: