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

> I thought that's why it's called "panic".

And you are exactly right.

The problem is: People are so used to the "exceptions" paradigm from other languages, when they see "panic-recover" many immediately think "That's the same thing!!"

It isn't, because the only VALID usecase for panics is exactly what you describe: unrecoverable error conditions where terminating the program is the best course of action.

`panic/recover` used like exceptions is an antipattern, and one of the worst code smells in a Go codebase.



You do need to use it, not to handle errors but to avoid it taking down the whole process (and probably sending some logs / alert / monitoring). Which doesn't apply everywhere, but at least in web dev it does: if a request / task panics, you want to abort just that, not the whole server including any other requests / tasks running.

Sadly, you need every goroutine to have its own recovery handler. This works well for your general request / task entrypoints, as there should only be one for each kind, but you need to watch out for any third-party libs spawning goroutines without recovery. They will take down your whole server.


That's not my experience. Other then the recover included in the http lib, I don't think I have ever used recover.

Why is you code panic'in? I would let it take down the process and figure out why. I have had backend programs set up to automatically restart, which can be useful. But I would treat any panic as a big deal.


You can treat panics as a big deal, and not necessarily kill the whole program. It's not mutually exclusive.

For example, at my work, we have some nightly long running tasks. We don't panic every day. But from time to time, let's say once or twice per month, some code changes cause a panic. On that day, we don't want to kill the long running tasks for no good reason other than somehow indirectly making someone fix the panic. We have alerts for that, and we're all grownups.


> You can treat panics as a big deal, and not necessarily kill the whole program. It's not mutually exclusive.

Yes it is mutually exclusive. Something that doesn't kill the program, aka a recoverable ERROR CONDITION should not cause a panic, that's not what panics exist for.

Something that causes a panic without using the `panic` keyword, like an out-of-bounds read, nil-derference, etc. is indicative of a serious problem that should be fixed before the program is allowed to run again.


> Something that doesn't kill the program, aka a recoverable ERROR CONDITION should not cause a panic

Can you explain why?

> a serious problem that should be fixed before the program is allowed to run again

Can you explain why the program should not be allowed to run again? Is this some sort of software spiritualism?


> Can you explain why?

Because that is semantically what a panic means in Go. See the link to effective go I posted you elsewhere in this thread.

I am well aware that it can be used in other ways. Same as I can say "car" when talking about a mainline battle-tank. Sure, a car has an engine, runs on fuel and drives on land. There are similarities. The words still mean very different things.

And I am also sure there have been instances of someone using a tank to go order food at a drive-through. Doesn't mean that it is semantically correct to do so, or advisable.


Your position is basically "there should be no recover() because you should never recover". Go itself disagrees, no matter how you interpret some "effective go" directive. See how many times it's used in the stdlib:

https://github.com/search?q=repo%3Agolang%2Fgo%20recover()&t...

It just doesn't make sense to take down the whole server, including all requests / jobs in flight, because there's some nil deref or out-of-bounds. Yea, that thing has to be fixed, but sending a specific alerts is much better than indirectly alerting by taking the whole system down.

If you're using go for something non-web, then it may very well make sense to not have recovery anywhere. Except of course you do have some, in the stdlib. But you can apply it to your code, if you want.

But it can't be some universal pragma (or convention) in go, as it violates the stdlib.


As I have said before, the fact that it is used, doesn't validate the usage. Yes, Go has recover. Yes, the stdlib uses it here and there.

Does any of that change the semantics of what a panic means, and how applications should therefore react? No. Does it make panics the equivalent of exceptions in Python semantically? Also no.

And this logic isn't limited to Go. Guess what, there are python libraries that use Exceptions for control flow. It certainly works. Does that validate using Exceptions as control flow elements? No, of course not. Why? Because that's not what an exception exists for semantically.

Panic-Recover cycles in go codebases are an antipattern, and unless I see an official statement by the people who make Go (who also write "Effective Go" btw.) saying otherwise, those are the semantics of the language.


It indicates that either programmer or at least operator (if E.G. this is a critical data validation fail), some sort of human, intervention is required. The situation must be evaluated critically before any further work occurs.


>your code

3P code is a thing

>why

Sometimes there are edge cases with nil pointers that testing missed.

>automatically restart

What about all of the other requests in flight? Letting those fail because one request hit an edge case isn't great for a production service with high throughput.


> if a request / task panics

...and the condition why it panics is not a situation that warrants a crash, then whatever is called upon handling that request is issueing a panic when it shouldn't.

The reason why some libs do that anyway is exactly what I describe above: because in many peoples minds panic == exception.

That's a logic error in the code and should get fixed. And one of the best ways to make devs fix things, is to let their application crash when something that shouldn't happen happens anyway, because then someone will start complaining why a service is unreachable.

TL;DR:

If some condition shouldn't crash a process, it has no earthly business causing a panic.


You're conflating unnecessary panics, with how to handle panics.

There will always be panics. You don't need to crash the thing to make devs notice, they're not idiots no matter what Rob Pike told you. You can alert and not throw out the baby with the bathwater. Nobody wants panics in their code, even if they're not crashing the whole world.


> You're conflating unnecessary panics, with how to handle panics.

I don't think so. If I have to handle a panic, because otherwise my program no longer works, one of 2 things is true in the vast majority of cases:

- There is something seriously wrong with the program or its environment, causing it to panic

- There is something in the program issueing a panic when really it should return an error

In short: there should be no need to "handle panics"

Panics are irrecoverable conditions where its preferable for the program to crash rather than continue. If code panicks for any other reason, thats, in my opinion, wrong, and should be fixed. Panics are not the equivalent to exceptions, and error returns exist for a reason.

People who don't like that paradigm can always use a language that uses the exception-paradigm.


> People who don't like that paradigm can always use a language that uses the exception-paradigm.

FYI the go std library recovers from panics when it spawns goroutines internally, in most cases.

All this has next to nothing to do with exceptions. Nobody is saying to use panics to pass errors or any control flow.


it only really does this for net/http, and it's considered a regrettable decision



Exactly, same as panic! in Rust.

There is a reason Rust was reluctant to add std::panic::catch_unwind at first. The docs thus explicitly mention that (1) it is not a typical exception mechanism and (2) that it might not even catch panics if unwinding is disabled (common for embedded and restricted development).


Also (3) there are panics that can't be safely caught, such as stack overflow.


There are even panics that are intended as irrecoverable: https://cs.opensource.google/go/x/sync/+/refs/tags/v0.12.0:s...


panic/recover is the same thing as exceptions. You can avoid them if you want, that's your decision, doesn't change the technical fact.


No it isn't. Semantics matter, and using something against the defined semantics of the language is a huge code smell.

For example, I could ignore the fact that Python has exceptions, and instead let functions return error values.

Would that work? Yes, absolutely, and I have seen Py-Codebases that do this.

Is it semantically correct? No, because in python, semantics dictate that error states are handled via exceptions, and that is the expectation everyone has when opening a python codebase.

When in Rome, do as the Romans do.


That's being idiomatic to a language, not being semantically correct.

Result, Either, Expected, all have different names, but their semantics are all the same.

Panic and Recover may not be idiomatically used the same way Exceptions are used in other languages, but they share the exact same semantics of implicitly bailing out potentially multiple functions, going up the call stack until we Catch, or well Recover.




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

Search: