Exceptions are already in the language: panic/recover. Though discouraged, you can't assume they won't happen. To me, this seems like the "worst of both worlds". It doesn't feel like a final position to me, it feels like a 1.0 position.
But panics are not exceptions. They should not be used like exceptions, and there is no "hierarchy of panic types".
They are used for things like out of bounds indexes, where in C it would simply be a segfault. A panic is a way of gracefully exiting a program that would have segfaulted otherwise. Correct code should check for out of bound indexes either way.
I agree, but would also point out that panic isn't necessarily going to exit a program, recover exists and it isn't that uncommon for programs or libraries to do a deferred recover at the beginning of goroutines so that a panic within that goroutine will only kill off that goroutine and allow the main goroutine and other goroutines to continue.
Of course this "pattern" should only be used when you're sure that that one failing goroutine won't have a cascading impact on other goroutines that are still running.
I think I've answered this elsewhere: the issue for me is that you have to handle exceptions _and_ error codes.
Though you raise an interesting point: Should you check array indexes if the runtime is also checking it for you?
In Java, the runtime is guaranteed to throw an exception and it is relatively rare that you would pre-check the array indexes (you might use assertions in debug code).
Incidentally, array bounds checking is actually relatively expensive, to the point where most JVMs (which use signed indexes) use an unsigned comparison trick to make it one comparison instead of two. So it does matter...
> the issue for me is that you have to handle exceptions _and_ error codes.
Except you don't. I haven't used recover in any of my code for a long time (more than a year). Most of the time you don't need to worry about handling panics, but you can if you really need to.
> Should you check array indexes if the runtime is also checking it for you?
In Go the generated code does it. You shouldn't do it yourself.
I consider defer to be part of handling exceptions, but I can see how we differ here.
We're seriously drifting off track here, but if we should rely on Go to check array indexes, that seems like you _would_ want a recover block, so that we can map it to a Go-preferred error code?
Go doesn't have exceptions. Can you please stop saying it does? There's a reason we didn't give "panic" the name "throw". Because they work differently and are used for different things.
There's also no such thing as a "recover block" (you're thinking of a "finally block" or "catch block", neither of which exist in Go).
If we thought you should use recover any time there might be an array out of bounds panic, we'd have designed the whole language differently. Panics should happen when things go badly wrong, and most of the time that means your program should crash.
You should use recover only in two rare cases: 1. where you're specifically using panic/recover as a kind of setjmp/longjmp (as it is used within encoding/json, for example), and 2. where you don't want a programming error to bring down your entire program, such as in the base net/http handler (although I think it's debatable whether we should have done it there; but it's done now and we can't change it).
It amazes me that there has been so much discussion over this incredibly minor and seldom-used feature. Just return and check errors (and just panic when things go really wrong) and get on with your life.
Doesn't the http package's Server recover from panics in the goroutines that are created to serve requests? That bugged me when I saw it happen. If my request handler panics, I wouldn't expect the server to recover from it.
You can abuse "panic" to implement exceptions in Golang the way you can abuse "longjmp" to do that in C. The purpose of "panic" isn't for general-purpose exceptions. It's to panic the program.
But correct code must assume that any function you call might throw; which is why you should use defer blocks e.g. to release resources, instead of C-style "cleanup at the bottom of the function". (Defer is also prettier IMHO)
It's idiomatically correct to ignore panics and let them take the whole program down with a crash. A panic indicates that your program is already doing extremely incorrect things. Rare is the program where picking itself up and continuing a possible Sorcerer's Apprentice mode rampage is better than just stopping and telling you what needs fixing.
Or raising?
That's just terminology. The behaviors of c++/java/python exceptions and Go panics are similar regardless of the name the keyword has in those language:
The execution is suspended, the stack unwound until the first handler, the handler has access to a value that is "thrown". Stack information is preserved in order to print meaningful stack traces.
C++/java/python have syntax sugar that performs a pattern match on the thrown object to decide whether to handle it or bubble it up, while in Go you do it manually, but other that that I don't see much of a difference in the mechanics of them to justify being so pedantic about the naming of the action.
The point is that an exception in Go world means: something which should not ever happen, and which renders continued execution impossible. IMO recover should only be used to wind down execution in as graceful a manner a possible prior to terminating the program.
As opposed to an error, which can and will happen.