Erlang's "let it die" philosophy is surrounded by other support structures that make it work. It works better in that language than it would in most others. I do find that my production-quality Erlang code does somewhat often have to catch errors so it can properly log them, though the relatively recent addition of line numbers is a big help there. (Prior to that, you could end up with a "badmatch" identified only by what function it occurred in. This is not necessarily a problem, but when you see dozens of them per minute filling up your log it made it tricky to figure out what was really going wrong so you could fix it. Even with line numbers it's not always quite enough, though.)

In Go, for that code snippet you'd be looking at one of two possibilities, looking at it a bit more generalized than just the specific Open call since I think this is a philosophical question rather than a literal "what does this code literally do?" question. Either "file" would come back nil, in which case the return line would crash with a nil access, or you'd get something that would fail to work correctly. Probably the zero value for the type, but only probably; it would be syntactically legal for the function to half-construct a value and end up returning it to you, expecting you to pick up the err value and know not to use it. I actually don't know what the common practice is here... obviously when I put it that way, returning a half-constructed object is not a good idea, but I don't know in practice whether many things do that, because you always should deal with the error. There is at least one call in the shipped library that can return both an error and a result, which is the Reader interface's Read call: http://golang.org/pkg/io/#Reader It is legal (though not mandatory) to both return that some bytes were read, and that we've hit the EOF. (It is mandatory that the next call will return only EOF as the error in that case.)

While Erlang and Go are at the opposite ends of the spectrum on error handling, and I think it's easy for either side to look at the other and think it's crazy, but I also think they're both solid ways of operating; in practice I find I produce similar levels of reliability with similar amounts of cognitive effort in both regimes. It's one of those cases where the extremes are viable, and it's the options in the middle that suck. In Erlang, you don't worry much about errors, the system is built around that, and the fact that "=" is not assignment but pattern-match-and-bind makes:

{ok, Value} = complicated_function()

into an efficient assertion that the function correctly completed and the correct thing is in Value xor I crashed. It makes a naive (in the computer science sense, not the insulting one), "sweep it under the rug" approach to errors do what it should. This is a huge positive... making simple code that anyone can write do the right thing is a very powerful approach, and failing to consider this is one of the Great Software Engineering Sins, in my opinion.

On the Go side, it mostly sticks errors in your face and makes damn sure you do something sensible with them. It's not perfect (it's possible to ignore an err... "someday" I'd like to build a go vet extension to help check for this), but it mostly doesn't let you ignore errors and write idiomatic code. Sure, it's more code than it needs to be, but, then, Erlang is not exactly a master of concision either (the number of multi-ugly-line Erlang functions that I could collapse down to one line of Haskell, sigh). This also works.

Partisans can have fruitful debates about the pros and cons of each. What doesn't work is making it so that naively-written code ends up completely ignoring errors and just then just skipping dealing with them. That said, honestly, nowadays I can only really think of C that still works that way, though. Most everything else has some solution to this problem (exceptions, mostly).