5 ms·
I would agree if it weren’t super easy to cause a panic in go. Index slice out of bounds? panic. Close a channel twice? Panic. Incorrect type assertion? Panic.
by BreakfastB0b 4y ago
I would agree if it weren’t super easy to cause a panic in go.
Index slice out of bounds? panic. Close a channel twice? Panic. Incorrect type assertion? Panic. Dereference nil pointer? Panic.
I would argue that all of these examples which are the most common in my experience are “goroutine scoped” because the goroutine was aborted before they potentially modified the application state in an unknown way.
It’s like not in C, or C++ where out of bounds access has now put the entire application into an unknown state.
- preseinger 4y ago> Index slice out of bounds? panic. Close a channel twice? Panic. Incorrect type assertion? Panic. Dereference nil pointer? Panic. These are all really bad things which should never survive to production code. It is not difficult to detect and prevent them. > I would argue that all of these examples which are the most common in my experience are “goroutine scoped” because the goroutine was aborted before they potentially modified the application state in an unknown way. What makes you think that terminating the goroutine that triggered these panics prevents them from impacting the process state? > It’s like not in C, or C++ where out of bounds access has now put the entire application into an unknown state. What makes you think this is the case? Panics have unknowable impact, and many panics (e.g. data races) absolutely do put the program into an unknown state.
- deleted 4y ago[deleted]
- Groxx 4y ago>These are all really bad things which should never survive to production code. It is not difficult to detect and prevent them. This is equivalent to saying "out of bounds memory writes are not difficult to detect and prevent in C code". Like actually equivalent (possibly worse), not just "well if you squint they look similar". Of course it's not hard most of the time. Being perfect is beyond hard though. And if you're not perfect, you might open the door to anything in C, or cluster-destroying rolling crashes in Go. Sometimes shutting down every piece of your software if that happens is the correct choice, and sometimes it's so far beyond reasonable that it's ludicrous to argue in favor of "every panic is an abort".
- groestl 4y ago> Sometimes shutting down every piece of your software if that happens is the correct choice, and sometimes it's so far beyond reasonable that it's ludicrous to argue in favor of "every panic is an abort". Very much this. And even for the same project: in some cases, I'm a fan of employing a quite strict error handling policy in dev environments (crash and burn) and using a more lenient approach in prod (elevated log level). In my experience, this can result in a robust product. Most importantly, this means the decision is not even made by the application programmer, sometimes it's a config thing.
- preseinger 4y agoGo has much stronger memory safety guarantees than C does. They aren't really comparable.
- erik_seaberg 4y agox == y can panic if interface values contain incomparable fields in unexported nested structs, how would I check for that? Should we let it become a query of death and bet thousands of peers’ jobs on it never happening?
- ikiris 4y agodon't do that? this kind of thing is why deepcompare exists to begin with
- aetherane 4y agoIt seems unrealistic to assume that everyone on a reasonably sized team knows all of the subtle edge cases to avoid and never makes mistakes
- deleted 4y ago[deleted]
- erik_seaberg 4y agoI can nag everyone to use reflect.DeepEqual and live with some false negatives, but maps always use k1 == k2.
- mappu 4y agoThis is days later, sorry, but - you can't use an interface as a map key, so this shouldn't apply, right?
- erik_seaberg 4y agohttps://go.dev/ref/spec#Map_types https://go.dev/ref/spec#Map_types says that is allowed. > If the key type is an interface type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.
- Groxx 4y agoThere are also significant performance and behavior differences between the two. They are not inter-changeable, nor can one replace the other.
- unscaled 4y ago> (e.g. data races) absolutely do put the program into an unknown state. Data races do not necessarily result in panics. Many (perhaps even most?) data races would not result in panic but just in garbled, missing, duplicate, out-of-order or otherwise incorrect data. Data-race induced panics are generally the side-effect of a data race, not a direct protection against. They can often be inconsistent: e.g. a data race in a slice that contains a binary data format could garble a variable-length string prefix and produce an index-out-of-bounds panic. Or it could prematurely consume a shared pointer and overwrite it with nil, only to have the nil pointer dereferenced by another goroutine. These kind of panics are unpredictable. If your application has shared global state (in-memory or even a database), it may become inconsistent due to data races. But whether data-race induced indicate irreversibly corrupted global state that requires (and can be fixed with) application restart - that is case-by-case thing. Let's say your application has some shared state that got corrupted and the corruption triggered a panic down the line. If your shared state is persisted in a database or some other distributed mechanism and that state got corrupted: restarting the application won't help you. If your shared state is scoped at the HTTP request level (or whichever boundary you choose for suppressing your panics): you don't need to restart the application. The request is already terminated, along with its shared state. Which leaves us with in-memory global state. This kind of state is generally minimized in the type of microservice and network infrastructure applications that Go is often used for. A very small percentage of your panics will indicate corruption of such state. Will you be willing to risk service downtime in order to protect against the small possibility that the service has run into a state where its shared in-memory data became corrupted? in memory or some other distributed mechanism and that state got corrupted: restarting the application won't help you.
- flippinburgers 4y agoI tend to agree with you that these are relatively easy things to detect. I see no reason for the downvotes. Production systems should have relatively robust testing whose coverage can be increased over time. When something panics, the cause of the panic should be fixed so that the panic never happens again. Over time panics shouldn't be happening. Then again the systems that I have relied on I have written on my own without other hands in the pot so maybe I just don't have to deal with the reality of other programmers phoning things in.