5 ms·
I'm not sure how great of an example it is, but I had the thought when recently rereading this routine from an old game, reading its level file: static
by graue 13y ago
I'm not sure how great of an example it is, but I had the thought when recently rereading this routine from an old game, reading its level file:
static void scanlevel(int num, FILE *fp)
{
filemap_t filemap;
int i;
if (fseek(fp, mapptrs[num-1], SEEK_SET))
error("Can't load level %d from blockman.lvl", num);
if (fread(&filemap, sizeof (filemap_t), 1, fp) < 1)
error("Can't load level %d from blockman.lvl", num);
if (filemap.startx < 0 || filemap.startx >= LEVWIDTH
|| filemap.starty < 0 || filemap.starty >= LEVHEIGHT)
{
error("Level %d is corrupt", num);
}
map.startx = filemap.startx;
map.starty = filemap.starty;
for (i = 0; i < LEVWIDTH*LEVHEIGHT; i++)
{
map.tiles[i] = (tiletype_t)filemap.tiles[i];
if (map.tiles[i] < 0 || map.tiles[i] >= NUMTILES)
error("Level %d is corrupt", num);
}
}
This shows another benefit of exceptions, which is that if uncaught, they stop the program with a traceback of the exact point they occurred. So it's not even necessary to write most of the checks above. `error` here is a routine that aborts the program; you get that behavior by default with exceptions.
Whereas in C/Go if I forgot one of those error checks, the error would occur silently, leaving the program in some weird inconsistent state that I never planned for. It would just do something stupid and maybe crash or panic later on, far from the place where the initial error occurred.
I guess I'm just arguing for exceptions, which is old news as languages that have them have been around for quite a while. But Go doesn't offer much of a substitute of which I'm aware. The explanation of how it solves these problems has not been forthcoming.
- zackelan 13y agoI think the key difference is between assertions/"this should never happen" error checking, and actual error conditions that you want to pass back to client code, because it knows better than you do what the right thing to do is. When you're writing reusable library code (and when you think about the scale of Google's codebase, they must have an insane amount of these libraries), it's important to make this distinction. There are some error conditions where you really just want to say "if this ever happens, just die, because there's nothing sane to be done", and Go provides panic() for these situations, similar to the error() function in your code above. For situations where you do want to return a meaningful error to the client, I think Go's multiple return values provide a very good way to do it, far better than the overloading of NULL or -1 that you find in C and C++.
- pacala 13y agoDoes panic isolate gracefully a query-of-death, or does it take the entire server down? Does panic provide the stack-trace?
- pjmlp 13y agoIf you don't use recover it takes the server down. http://blog.golang.org/2010/08/defer-panic-and-recover.html http://blog.golang.org/2010/08/defer-panic-and-recover.html http://code.google.com/p/go-wiki/wiki/PanicAndRecover http://code.google.com/p/go-wiki/wiki/PanicAndRecover
- EdiX 13y agoA panic unrolls the stack until it's recovered from. If it's not recovered the entire server will go down. If the panic isn't recovered it will print a stack trace, if it is recovered you can get a stack trace with runtime.Caller(). Go's panics are exceptions.
- pacala 13y agoThanks!
- azth 13y ago> I think Go's multiple return values provide a very good way to do it... Better than C? Sure. But not better than languages that provide sum types; some of which have been around since the 70s.
- MetaCosm 13y agoThe list of cool things Go doesn't have is a darn long one. They opted for simplicity at lots of points. I think it is worth noting these were decisions, not necessarily oversights. There are a lot of great languages that end up mostly academic because they lack whatever the magical balance of features, simplicity and usefulness it takes for a language get mind share. I suspect Go might have hit the magical balance with channels, strong types, great build system, simple minimal syntax and language keywords, fairly opinionated best practices (and formatting) and static single file deploys.
- nknighthb 13y agoI'm not clear on which error check you think you might "forget". If you're performing an operation that can fail, wouldn't that be a clue that you need to check for failure? You can't actually write code like that in Go, by the way. It's not going to let you read data directly into a struct like that, nor should you really be doing so in the first place. I'd be happy to provide a more detailed analysis, and possibly even Go-equivalent code, but without further context (at least the definitions for `filemap_t` and whatever struct type `map` is, if not a full description of the file format and its meaning), it's impractical.
- AlisdairO 13y ago> I'm not clear on which error check you think you might "forget". If you're performing an operation that can fail, wouldn't that be a clue that you need to check for failure? Sure - and the possibility of exceeding the bounds of an array would be a clue that you need to bounds check, but there's still a hell of a lot of C code out there with array overflow errors. You can argue that people who make these errors are bad programmers, but that's fairly irrelevant - most programmers of any level will end up working with code with errors in it at some point. Exception stack traces are an extremely useful way to find out where something went wrong when someone failed to do some necessary error checking. I have no experience with Go, so I'm not saying what it does is wrong - I'm just curious. Say a customer experiences a failure with your software caused by some missing/incorrect error handling, what do you do to work out what happened?
- nknighthb 13y ago> the possibility of exceeding the bounds of an array Not possible in Go, the runtime will panic. > there's still a hell of a lot of C code out there with array overflow errors An extremely easy error to make in many cases, which is why modern programming languages bounds-check. > Exception stack traces Go will give you a very nice stacktrace should it ever panic. > I have no experience with Go Which is really the problem. People keep arguing about Go's merits based on no substantive understanding. It's very obvious which operations can fail without a panic in Go, because functions explicitly return error objects -- actual error objects, not magic numbers. The return signature for the Go equivalent of fread is (int, error), not (int).
- grey-area 13y agoThe explanation of how it solves these problems has not been forthcoming. It'd be interesting to see what you'd do with the code above in C++, and where you'd put the error handling code for diverse errors that might occur reading this particular file. The Go approach is to handle errors locally, often in the calling method, which makes it clear where they are handled and what the outcome is, and easier to recover gracefully, without unexpected exceptions from code in libraries or other code in the program. Some large users of C++ (like Google) refuse to use C++ exceptions in their own code - so they are not entirely without controversy. In the code above, if you used exceptions, and relied on the libraries to throw exceptions for errors, you'd have to throw your own exception at: error("Level %d is corrupt", num); So you'd have a mix places where exceptions were generated (in unknown lib code, in your code) and an unknown (for the reader) mix of places where they are handled. I'm sure this could be done gracefully, but it does mean errors missed might be handled at a much higher level in the code, far away from where they were generated, which can lead to errors being missed until it is too late to do anything but output a stack trace and exit, which to the user seems equally stupid as crashing or panicking at some later point. If you exit the program on simple errors like being unable to load a single game file, it's not very pleasant for the user - I'd expect it instead to recover gracefully and show the user an error before continuing, which is easy enough when using Go's pattern of error returns, and harder with exceptions where you have unrolled the stack possibly past the loading code, unless you start handling exceptions in calling code one level up, which looks very much like the error handling of Go. So there are trade-offs to using either method aren't there?
- azth 13y agoNot using C++ exceptions in Google's code bases is partly due to historic reasons (since the original code base did not have it), and partly due to them being "harder" to implement in C++ correctly. They even acknowledge in their C++ style guide[1] that: " Things would probably be different if we had to do it all over again from scratch." [1] http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Exceptions http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...